[med-svn] [fis-gtm] 01/04: Imported Upstream version 6.2-001

Amul Shah tuskentower-guest at moszumanska.debian.org
Fri Jan 23 00:10:02 UTC 2015


This is an automated email from the git hooks/post-receive script.

tuskentower-guest pushed a commit to branch master
in repository fis-gtm.

commit 921cb3013bf8f25b14a24e70ef612d3153eb4011
Author: Amul Shah <Amul.Shah at fisglobal.com>
Date:   Sun Jan 11 19:56:27 2015 -0500

    Imported Upstream version 6.2-001
---
 CMakeLists.txt                                     |   55 +-
 README                                             |   46 +-
 sr_avms/release_name.h                             |    2 +-
 sr_i386/merrors_ansi.h                             |   27 +-
 sr_i386/merrors_ctl.c                              |   64 +-
 sr_i386/obj_file.c                                 |   26 +-
 sr_linux/hugetlbfs_overrides.h                     |   25 -
 sr_linux/release_name.h                            |   10 +-
 sr_port/advancewindow.c                            |   16 +-
 sr_port/buddy_list.c                               |    5 +-
 sr_port/ceil_log2.c                                |   77 +
 sr_port/cmd.c                                      |    8 +-
 sr_port/code_gen.c                                 |    3 +-
 sr_port/comp_fini.c                                |    4 +-
 sr_port/comp_init.c                                |    7 +-
 sr_port/compile_pattern.c                          |    5 +-
 sr_port/compiler_startup.c                         |    3 +-
 sr_port/db_auto_upgrade.c                          |    9 +-
 sr_port/db_csh_getn.c                              |   72 +-
 sr_port/dbcertify_certify_phase.c                  |   91 +-
 sr_port/dbcertify_scan_phase.c                     |   27 +-
 sr_port/dse.hlp                                    |   28 +-
 sr_port/dse_adrec.c                                |    4 +-
 sr_port/dse_chng_fhead.c                           |    9 +-
 sr_port/dse_getki.c                                |    2 -
 sr_port/dump_record.c                              |    4 +-
 sr_port/entryref.c                                 |    2 +-
 sr_port/error.h                                    |    2 +
 sr_port/exfunc.c                                   |    2 +-
 sr_port/expritem.c                                 |    4 +-
 sr_port/f_get.c                                    |    4 +-
 sr_port/f_name.c                                   |    4 +-
 sr_port/f_order.c                                  |    4 +-
 sr_port/find_rtn_hdr.c                             |   69 +-
 sr_port/flush_jmp.c                                |   16 +-
 sr_port/format2disp.c                              |   88 +
 sr_port/gbldefs.c                                  |    8 +-
 sr_port/gde.hlp                                    |   18 +-
 sr_port/gdsbt.h                                    |    6 +-
 sr_port/gdsdbver.h                                 |    3 +-
 sr_port/gdsfhead.h                                 |   71 +-
 sr_port/gtm_env_init.c                             |   18 +
 sr_port/gtm_stdlib.h                               |   56 +-
 sr_port/gtm_threadgbl.h                            |    7 +-
 sr_port/gtm_threadgbl_defs.h                       |   45 +-
 sr_port/gtm_threadgbl_deftypes.c                   |    5 +-
 sr_port/gtm_threadgbl_init.c                       |    9 +-
 sr_port/gtmrecv_helpers_init.c                     |   38 +-
 sr_port/gtmrecv_upd_proc_init.c                    |   45 +-
 sr_port/gv_select.c                                |   60 +-
 sr_port/gv_trigger_common.h                        |   23 +-
 sr_port/gvcst_init.c                               |   44 +-
 sr_port/hashtab.h                                  |   93 +-
 sr_port/have_crit.h                                |    3 +-
 sr_port/indir.h                                    |    2 +-
 sr_port/indirection.c                              |    4 +-
 sr_port/io_rundown.c                               |    6 +-
 sr_port/iosocket_close.c                           |   29 +-
 sr_port/iosocket_flush.c                           |   24 +-
 sr_port/iosocket_iocontrol.c                       |   95 +-
 sr_port/iosocket_readfl.c                          |   17 +-
 sr_port/iosocket_snr.c                             |  140 +-
 sr_port/iosocket_use.c                             |    7 +
 sr_port/iosocket_wait.c                            |   95 +-
 sr_port/iosocket_write.c                           |  293 +++-
 sr_port/iosocketdef.h                              |   26 +-
 sr_port/jnl.h                                      |   38 +-
 sr_port/jnl_file_open_common.c                     |    3 +-
 sr_port/jnl_file_open_switch.c                     |   11 +-
 sr_port/jnl_write.c                                |    3 +-
 sr_port/jnl_write_poolonly.c                       |    3 +
 sr_port/job_addr.c                                 |   23 +-
 sr_port/job_addr.h                                 |    4 +-
 sr_port/jobparams.h                                |    3 +-
 sr_port/jobparamstrs.h                             |    5 +-
 sr_port/lke.hlp                                    |    9 +-
 sr_port/lvzwr_init.c                               |    5 +-
 sr_port/lvzwr_var.c                                |   18 +-
 sr_port/m_do.c                                     |    2 +-
 sr_port/m_zstep.c                                  |    4 +-
 sr_port/m_zwrite.c                                 |    4 +-
 sr_port/maketriple.c                               |    5 +-
 sr_port/md5_digest2hex.c                           |   40 -
 sr_port/mdef.h                                     |   70 +-
 sr_port/merrors.msg                                |   35 +-
 sr_port/mtables.c                                  |   27 +-
 sr_port/mu_extr_ident.c                            |   18 +-
 sr_port/muextr.h                                   |   12 +-
 sr_port/mumps.hlp                                  |  694 ++++----
 sr_port/mupip.hlp                                  |  299 ++--
 sr_port/mupip_cvtgbl.h                             |    6 +-
 sr_port/mupip_reorg.c                              |   12 +-
 sr_port/mupip_set_journal_parse.c                  |   16 +-
 sr_port/mv_stent.h                                 |   21 +-
 sr_port/obj_file.h                                 |   34 +-
 sr_port/objlabel.h                                 |    2 +-
 sr_port/one_job_param.c                            |    8 +-
 sr_port/op_exp.c                                   |   94 +-
 sr_port/op_fntext.c                                |   29 +-
 sr_port/op_fnview.c                                |   84 +-
 sr_port/op_fnztrigger.c                            |   34 +-
 sr_port/op_hang.c                                  |   11 +-
 sr_port/op_indpat.c                                |    4 +-
 sr_port/op_indtext.c                               |    4 +-
 sr_port/op_lvpatwrite.c                            |    5 +-
 sr_port/op_lvzwrite.c                              |    5 +-
 sr_port/op_merge.c                                 |    2 +
 sr_port/op_rhdaddr.c                               |    6 +-
 sr_port/op_setzbrk.c                               |   65 +-
 sr_port/op_svget.c                                 |   15 +-
 sr_port/op_tcommit.c                               |    4 +-
 sr_port/op_tstart.c                                |   19 +-
 sr_port/op_unwind.c                                |    5 +
 sr_port/op_view.c                                  |  151 +-
 sr_port/op_zprint.c                                |   69 +-
 sr_port/op_zshow.c                                 |   14 +-
 sr_port/opcode_def.h                               |    2 +
 sr_port/put_indr.c                                 |   15 +-
 sr_port/put_lit.c                                  |   10 +-
 sr_port/put_str.c                                  |    5 +-
 sr_port/repl_errno.h                               |   11 +-
 sr_port/repl_filter.c                              |  345 ++--
 sr_port/repl_filter.h                              |   38 +-
 sr_port/rtn_src_chksum.c                           |   25 +-
 sr_port/rtn_src_chksum.h                           |    8 +-
 sr_port/s2n.c                                      |    3 +-
 sr_port/srcline.h                                  |   33 +-
 sr_port/stp_gcol_src.h                             |   32 +-
 sr_port/svnames.h                                  |    3 +-
 sr_port/t_end.c                                    |    4 +-
 sr_port/t_end_sysops.c                             |    7 +-
 sr_port/tab_gvstats_rec.h                          |   12 +-
 sr_port/tp.h                                       |   22 +-
 sr_port/tp_clean_up.c                              |   18 +-
 sr_port/tp_incr_clean_up.c                         |    6 +-
 sr_port/tp_tend.c                                  |   33 +-
 sr_port/unw_mv_ent.c                               |   18 +-
 sr_port/unw_retarg.c                               |   38 +-
 sr_port/updhelper_reader.c                         |    1 -
 sr_port/updproc.c                                  |   36 +-
 sr_port/updproc.h                                  |   47 +-
 sr_port/updproc_get_gblname.c                      |   13 +-
 sr_port/util.h                                     |   25 +-
 sr_port/verify_queue.c                             |   72 +-
 sr_port/view_arg_convert.c                         |   30 +-
 sr_port/viewtab.h                                  |    9 +-
 sr_port/wbox_test_init.h                           |   17 +-
 sr_port/xfer.h                                     |    2 +-
 sr_port/zbreak.h                                   |    8 +-
 sr_port/zlput_rname.c                              |  103 +-
 sr_port/{zr_get_free.c => zr_add_zbreak.c}         |   12 +-
 sr_port/{zr_put_free.c => zr_remove_zbreak.c}      |   42 +-
 sr_port/zr_remove_zbrks.c                          |   15 +-
 sr_port/zr_unlink_rtn.c                            |   35 +-
 sr_port/zshow.h                                    |    7 +-
 sr_port/zshow_output.c                             |   55 +-
 sr_port/zshow_svn.c                                |   16 +-
 sr_unix/CMakeLists.txt                             |   53 +-
 sr_unix/Makefile.mk                                |  138 +-
 sr_port/md5_digest2hex.h => sr_unix/arlinkdbg.h    |   23 +-
 sr_unix/auto_zlink.c                               |   20 +-
 sr_unix/bin_load.c                                 |   68 +-
 sr_unix/buildaux.csh                               |   57 +-
 sr_unix/callintogtmxfer.c                          |   10 +-
 sr_unix/ce_substitute.c                            |    4 +-
 sr_unix/cli.h                                      |    6 +-
 sr_unix/cli_parse.c                                |    2 +-
 sr_unix/comlist.csh                                |   49 +-
 sr_unix/comp_lits.c                                |   23 +-
 sr_unix/dbcertify_signal_handler.c                 |   23 +-
 sr_unix/do_shmat.c                                 |   51 +-
 sr_unix/do_shmat.h                                 |    5 +-
 sr_unix/dollarh.c                                  |   21 +-
 sr_unix/dsk_read.c                                 |    7 +-
 sr_unix/errorsp.h                                  |    2 +
 sr_port/lastchance3.c => sr_unix/exi_ch.c          |   22 +-
 sr_unix/file_input.c                               |  113 +-
 sr_unix/file_input.h                               |   21 +-
 sr_unix/ftok.c                                     |    3 +
 sr_unix/generate_help.csh                          |  102 ++
 sr_unix/get_src_line.c                             |   63 +-
 sr_unix/geteditor.c                                |   13 +-
 sr_unix/go_load.c                                  |   72 +-
 sr_unix/grab_latch.c                               |   84 +
 sr_unix/gt_timer.h                                 |   68 +-
 sr_unix/gt_timers.c                                |  112 +-
 sr_unix/gtm_env_init_sp.c                          |   41 +-
 sr_unix/gtm_exit_handler.c                         |  156 +-
 sr_unix/gtm_ipc.h                                  |    6 +-
 sr_unix/gtm_logicals.h                             |    6 +-
 sr_unix/gtm_permissions.c                          |   43 +-
 sr_unix/gtm_permissions.h                          |    7 +-
 sr_unix/gtm_semutils.h                             |   10 +-
 sr_unix/gtm_startup.c                              |   10 +-
 sr_unix/gtm_stdio.h                                |   14 +-
 sr_unix/gtm_tls.h                                  |    8 +-
 sr_unix/gtm_tls_impl.c                             |  519 +++++-
 sr_unix/gtm_tls_impl.h                             |    5 +-
 sr_unix/gtm_tls_interface.h                        |   54 +-
 sr_unix/gtm_trigger.c                              |   33 +-
 sr_unix/gtm_trigger.h                              |   26 +-
 sr_unix/gtm_trigger_trc.h                          |    4 +-
 sr_unix/gtmci.c                                    |   12 +-
 sr_unix/gtmcrypt_interface.h                       |   44 +-
 sr_unix/gtmcrypt_util.c                            |   32 +-
 sr_unix/gtmcrypt_util.h                            |   14 +-
 sr_unix/gtminstall.sh                              |    5 +
 sr_unix/gtminstall_Solaris.sh                      |    5 +
 sr_unix/gtmio.h                                    |   19 +-
 sr_unix/gtmprofile.gtc                             |   10 +-
 sr_unix/gtmrecv_process.c                          |  104 +-
 sr_unix/gtmsecshr.c                                |   14 +-
 sr_unix/gtmsource.c                                |    3 +-
 sr_unix/gtmsource.h                                |   22 +-
 sr_unix/gtmsource_get_opt.c                        |    3 +-
 sr_unix/gtmsource_process.c                        |   21 +-
 sr_unix/gtmsource_process_ops.c                    |    7 +-
 sr_unix/gtmsource_readfiles.c                      |   19 +-
 sr_unix/gtmsrc.csh                                 |    4 +-
 sr_unix/gv_trigger.c                               |   91 +-
 sr_unix/gv_trigger.h                               |   76 +-
 sr_unix/gv_trigger_protos.h                        |   13 +-
 sr_unix/gvcst_init_sysops.c                        |   18 +-
 sr_unix/hugetlbfs_overrides.h                      |   34 +
 sr_unix/incr_link.c                                |  352 +++-
 sr_unix/incr_link.h                                |   26 +-
 sr_unix/init_gtm.c                                 |    6 +-
 sr_unix/interlock.h                                |   14 +-
 sr_unix/iopi_open.c                                |  132 +-
 sr_unix/iosocket_tls.c                             |  357 ++++
 sr_unix/jnlpool_init.c                             |    2 +-
 sr_unix/jobchild_init.c                            |   28 +-
 sr_unix/jobsp.h                                    |   10 +-
 sr_unix/kitstart.csh                               |   14 +-
 sr_unix/libmupip.list                              |    3 +
 sr_unix/load.h                                     |    4 +-
 sr_unix/m_zrupdate.c                               |    2 +-
 sr_unix/maskpass.c                                 |   57 +-
 sr_unix/mdefsp.h                                   |   23 +-
 sr_unix/mmrhash.c                                  |  500 +++++-
 sr_unix/mmrhash.h                                  |   30 +-
 sr_unix/mu_all_version_standalone.c                |   45 +-
 sr_unix/mu_rndwn_file.c                            |    2 +-
 sr_unix/mu_rndwn_rlnkctl.c                         |   65 +
 sr_unix/{do_shmat.h => mu_rndwn_rlnkctl.h}         |   10 +-
 sr_unix/mupip_cmd.c                                |   29 +-
 sr_unix/mupip_cmd_disallow.c                       |    6 +-
 sr_unix/mupip_cvtgbl.c                             |  128 +-
 sr_unix/mupip_exit_handler.c                       |    2 +-
 sr_unix/mupip_hash.c                               |   65 +
 sr_avms/release_name.h => sr_unix/mupip_hash.h     |    6 +-
 sr_unix/mupip_rctldump.c                           |   60 +
 sr_unix/{do_shmat.h => mupip_rctldump.h}           |   10 +-
 sr_unix/mupip_rundown.c                            |    2 +-
 sr_unix/mupip_trigger.c                            |   65 +-
 sr_unix/mutex.c                                    |  115 +-
 sr_unix/mutexsp.h                                  |    4 +-
 sr_unix/obj_code.c                                 |   79 +-
 sr_unix/obj_file.c                                 |  199 ++-
 sr_unix/obj_filesp.h                               |    3 +-
 sr_unix/obj_fileu.c                                |  147 ++
 sr_unix/ojchildioclean.c                           |    5 +-
 sr_unix/ojchildparms.c                             |  177 +-
 sr_unix/ojparams.c                                 |    6 +-
 sr_unix/ojstartchild.c                             |  221 ++-
 sr_unix/op_fnzpeek.c                               |   91 +-
 sr_unix/op_fnzsearch.c                             |    2 +-
 sr_unix/op_lab_ext.c                               |    4 +-
 sr_unix/op_rhd_ext.c                               |   47 +-
 sr_unix/op_zedit.c                                 |   17 +-
 sr_unix/op_zlink.c                                 |  222 ++-
 sr_unix/op_zrupdate.c                              |  184 +-
 sr_unix/open_object_file.c                         |  111 --
 sr_unix/parse_file.h                               |    8 +-
 .../md5_digest2hex.h => sr_unix/probecrit_rec.h    |   25 +-
 sr_unix/rel_latch.c                                |   31 +
 sr_unix/relinkctl.c                                |  849 ++++++---
 sr_unix/relinkctl.h                                |  284 ++-
 sr_unix/repl_inst_dump.c                           |    6 +-
 sr_unix/repl_msg.h                                 |   14 +-
 sr_unix/rtnhdr.h                                   |   68 +-
 sr_unix/rtnobj.c                                   |  997 +++++++++++
 sr_unix/rtnobj.h                                   |   34 +
 sr_unix/runall.csh                                 |    9 +-
 sr_unix/secshr_client.c                            |   21 +-
 sr_unix/sleep.c                                    |   64 +-
 sr_unix/sleep.h                                    |  255 ++-
 sr_unix/ss_context_mgr.c                           |   16 +-
 sr_unix/tab_probecrit_rec.h                        |   23 +
 sr_unix/trigger.h                                  |  225 ++-
 sr_unix/trigger_compare.c                          |  220 ++-
 sr_unix/trigger_compare_protos.h                   |    4 +-
 sr_unix/trigger_delete.c                           |  772 ++++-----
 sr_unix/trigger_delete_protos.h                    |    8 +-
 sr_unix/trigger_fill_xecute_buffer.c               |   12 +-
 sr_unix/trigger_gbl_fill_xecute_buffer.c           |   59 +-
 sr_unix/trigger_parse.c                            |   52 +-
 sr_unix/trigger_read_name_entry.c                  |   66 -
 sr_unix/trigger_read_name_entry.h                  |   17 -
 sr_unix/trigger_select.c                           |  454 +++--
 sr_unix/trigger_select_protos.h                    |   12 +-
 sr_unix/trigger_source_read_andor_verify.c         |  446 +++--
 sr_unix/trigger_source_read_andor_verify.h         |    4 +-
 sr_unix/trigger_subs_def.h                         |   32 +-
 sr_unix/trigger_trgfile.c                          |  114 +-
 sr_unix/trigger_update.c                           | 1808 ++++++++++++--------
 sr_unix/trigger_update_protos.h                    |   37 +-
 sr_unix/trigger_upgrade.c                          |  542 ++++++
 sr_unix/{do_shmat.h => trigger_upgrade_protos.h}   |    8 +-
 sr_unix/util_out_print_gtmio.c                     |  134 ++
 sr_unix/util_output.c                              |   52 +-
 sr_unix/wcs_flu.c                                  |   30 +-
 sr_unix/zhist.c                                    |  104 +-
 sr_unix/zhist.h                                    |   42 -
 sr_unix/zro_gettok.c                               |   51 +-
 sr_unix/zro_load.c                                 |   38 +-
 sr_unix/zro_search.c                               |  233 ++-
 sr_unix/zroutinessp.h                              |    5 +-
 sr_unix/zshow_devices.c                            | 1029 +++++------
 sr_unix/zshow_rctldump.c                           |   96 ++
 sr_unix_nsb/obj_code.c                             |   14 +-
 sr_unix_nsb/obj_filesp.h                           |   12 +-
 sr_unix_nsb/rtnhdr.h                               |    4 +-
 sr_vvms/dbcertify_exit_handler.c                   |   15 +-
 sr_vvms/get_src_line.c                             |   14 +-
 sr_vvms/gt_timers.c                                |    6 +-
 sr_vvms/gtm$startup.c                              |    5 +-
 sr_vvms/gtm_logicals.h                             |    5 +-
 sr_vvms/gtmrecv_process.c                          |    6 +-
 {sr_port => sr_vvms}/lastchance1.c                 |    0
 {sr_port => sr_vvms}/lastchance2.c                 |    2 +-
 {sr_port => sr_vvms}/lastchance3.c                 |    2 +-
 sr_vvms/op_fnzsearch.c                             |    2 +-
 {sr_port => sr_vvms}/op_setzbrk.c                  |   65 +-
 sr_vvms/rtnhdr.h                                   |    2 +-
 sr_x86_64/merrors_ansi.h                           |   27 +-
 sr_x86_64/merrors_ctl.c                            |   64 +-
 sr_x86_64/obj_filesp.c                             |    9 +-
 338 files changed, 14674 insertions(+), 6827 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9bb017b..04203d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@ foreach(lang ${languages})
 endforeach()
 
 # Defaults
-set(version V6.2-000)
+set(version V6.2-001)
 if("${version}" STREQUAL "")
         set(version V9.9-0)
 endif()
@@ -60,8 +60,6 @@ set(gtm_osarch_libs "")
 set(gt_src_list)
 set(sources_used "")
 set(extralibs "")
-set(GTMCRYPTLIB "GCRYPT")
-set(GTMCRYPTALGO "AES256CFB")
 message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
 # Establish platform
 # Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true
@@ -76,7 +74,6 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
 else()
   message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
 endif()
-message("--> Encryption Library = ${GTMCRYPTLIB} / Algorithm = ${GTMCRYPTALGO}")
 
 # Choose where to get bootstrap sources.
 set(GTM_DIST "" CACHE PATH "Existing GT.M Distribution")
@@ -461,14 +458,50 @@ foreach(tlslib ssl crypto config)
   set(TLS_LIBRARIES ${TLS_LIBRARIES} ${TLSLIB_${tlslib}})
 endforeach()
 
-add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES})
-set_target_properties(libgtmcrypt PROPERTIES
-  OUTPUT_NAME gtmcrypt
-  COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_${GTMCRYPTALGO}"
+# Building the three encryption libraries could by a loop of some sort, but
+# manually creating each target is way easier.
+
+# Library=GCRYPT Algorithm=AES256CFB
+add_library(libgtmcrypt_gcrypt_AES256CFB.so MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_gcrypt_AES256CFB.so PROPERTIES
+  OUTPUT_NAME gtmcrypt_gcrypt_AES256CFB
+  COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB"
+  LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+  )
+target_link_libraries(libgtmcrypt_gcrypt_AES256CFB.so ${GPG_LIBRARIES})
+install(TARGETS libgtmcrypt_gcrypt_AES256CFB.so DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Establish the default encryption link
+set(default_encr_link   ${GTM_BINARY_DIR}/plugin/libgtmcrypt.so)
+set(default_encr_target libgtmcrypt_gcrypt_AES256CFB.so)
+add_custom_command(
+	OUTPUT ${default_encr_link}
+	COMMAND ${CMAKE_COMMAND} -E create_symlink "${default_encr_target}" "${default_encr_link}"
+	DEPENDS ${GTM_BINARY_DIR}/plugin/${default_encr_target}
+	COMMENT "Generating default_encr symbolic link"
+	)
+add_custom_target(install_default_encr ALL DEPENDS ${default_encr_link})
+install(FILES ${default_encr_link} DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=AES256CFB
+add_library(libgtmcrypt_openssl_AES256CFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_AES256CFB PROPERTIES
+  OUTPUT_NAME gtmcrypt_openssl_AES256CFB
+  COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_AES256CFB"
+  LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+  )
+target_link_libraries(libgtmcrypt_openssl_AES256CFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_AES256CFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=BLOWFISHCFB
+add_library(libgtmcrypt_openssl_BLOWFISHCFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_BLOWFISHCFB PROPERTIES
+  OUTPUT_NAME gtmcrypt_openssl_BLOWFISHCFB
+  COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_BLOWFISHCFB"
   LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
   )
-target_link_libraries(libgtmcrypt ${GPG_LIBRARIES})
-install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin)
+target_link_libraries(libgtmcrypt_openssl_BLOWFISHCFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_BLOWFISHCFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
 
 add_library(libgtmtls MODULE ${libgtmtls_SOURCES})
 set_target_properties(libgtmtls PROPERTIES
@@ -482,7 +515,7 @@ install(TARGETS libgtmtls DESTINATION ${GTM_INSTALL_DIR}/plugin)
 add_executable(maskpass ${maskpass_SOURCES})
 target_link_libraries(maskpass ${GPG_LIBRARIES} ${TLS_LIBRARIES})
 set_target_properties(maskpass PROPERTIES
-  COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_SYSLIB_FUNCS"
+  COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_SYSLIB_FUNCS"
   RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt
   )
 install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt)
diff --git a/README b/README
index 43fd188..53a67e2 100644
--- a/README
+++ b/README
@@ -10,32 +10,36 @@ 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.
+(either x86 or x86_64), libraries and development files for libz, Unicode,
+OpenSSL and GPG. Debian 6, Ubuntu 12.04/14.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.
+   libgcrypt, libssl, libconfig.
 
    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.
+   Manual if you do encounter these messages. The following should give you a
+   valid locale:
+
+   $ locale -a | gawk 'BEGIN{IGNORECASE=1}/en_us.utf-*8/{print;exit}'
+   en_US.utf8
+   $ export LANG=C LC_ALL= LC_CTYPE="<answer from above>" LC_COLLATE=C
 
    [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.2-000 is /opt/fis-gtm/V6.2-000_i586 or
-   /opt/fis-gtm/V6.2-000_x8664. These instructions are written using x8664, please
+   Base (LSB) install path for GT.M V6.2-001 is /opt/fis-gtm/V6.2-001_i586 or
+   /opt/fis-gtm/V6.2-001_x8664. These instructions are written using x8664, please
    use i586 as necessary.
 
-   $ tar xfz gtm_V62000_linux_x8664_pro.tar.gz
+   $ tar xfz gtm_V62001_linux_x8664_pro.tar.gz
 
    # Note down the installation path for use with cmake below
 
@@ -43,16 +47,16 @@ To build GT.M for Linux, do the following steps:
 
 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.2-000
-   $ tar xfz fis-gtm-V6.2-000.tar.gz
-   $ cd fis-gtm-V6.2-000
+   the name, fis-gtm-V6.2-001
+   $ tar xfz fis-gtm-V6.2-001.tar.gz
+   $ cd fis-gtm-V6.2-001
 
    You should find this README, LICENSE, COPYING and CMakeLists.txt file and
    sr_* source directories.
 
 3. Building GT.M -
    <fis-gtm-build> can be a sub directory of the source directory,
-   fis-gtm-V6.2-000, or any other valid path.
+   fis-gtm-V6.2-001, or any other valid path.
 
    $ mkdir <fis-gtm-build>
    $ cd <fis-gtm-build>
@@ -71,16 +75,16 @@ To build GT.M for Linux, do the following steps:
    #
    #     -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package
    #
-   $ cmake -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package <path to>/fis-gtm-V6.2-000
+   $ cmake -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package <path to>/fis-gtm-V6.2-001
 
    $ make
 
    $ make install
 
-   $ cd package/lib/fis-gtm/V6.2-000_x86_64
+   $ cd package/lib/fis-gtm/V6.2-001_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.2-000_x86_64
+   # The recommended installation path is /opt/fis-gtm/V6.2-001_x86_64
 
    $ sudo ./configure
 
@@ -88,3 +92,11 @@ To build GT.M for Linux, do the following steps:
 
 4. Packaging GT.M -
    Create a tar file from the installed directory
+
+FAQ:
+- The CMake build fails with the following message followed by one or more cases.
+	CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
+	Please set them or make sure they are set and tested correctly in the CMake files:
+  This indicates that required libraries are not found. Please consult the list
+  of libraries and check your distributions package manager.
+
diff --git a/sr_avms/release_name.h b/sr_avms/release_name.h
index 632b116..293a521 100644
--- a/sr_avms/release_name.h
+++ b/sr_avms/release_name.h
@@ -9,6 +9,6 @@
  *								*
  ****************************************************************/
 
-#define GTM_RELEASE_NAME	"GT.M V6.2-000 VMS AXP"
+#define GTM_RELEASE_NAME	"GT.M V6.2-001 VMS AXP"
 #define GTM_PRODUCT		"GT.M"
 #define GTM_VERSION		"V6.2"
diff --git a/sr_i386/merrors_ansi.h b/sr_i386/merrors_ansi.h
index 20e9320..f00646a 100644
--- a/sr_i386/merrors_ansi.h
+++ b/sr_i386/merrors_ansi.h
@@ -609,7 +609,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* FREEZEID */
 	   0,	/* BLKWRITERR */
 	   0,	/* STOPTIMEOUT */
-	   0,	/* TRIGMODINTP */
+	   0,	/* UNUSEDMSG776 */
 	   0,	/* BCKUPBUFLUSH */
 	   0,	/* NOFORKCORE */
 	   0,	/* JNLREAD */
@@ -731,7 +731,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* SCNDDBNOUPD */
 	   0,	/* MUINFOUINT4 */
 	   0,	/* NLMISMATCHCALC */
-	   0,	/* UNUSEDMSG898 */
+	   0,	/* RELINKCTLFULL */
 	   0,	/* UNUSEDMSG899 */
 	   0,	/* DBBADNSUB */
 	   0,	/* DBBADKYNM */
@@ -1200,13 +1200,13 @@ const static readonly int error_ansi[] = {
 	   0,	/* SSATTACHSHM */
 	   0,	/* TRIGDEFNOSYNC */
 	   0,	/* TRESTMAX */
-	   0,	/* UNUSEDMSG1367 */
+	   0,	/* ZLINKBYPASS */
 	   0,	/* GBLEXPECTED */
 	   0,	/* GVZTRIGFAIL */
 	   0,	/* MUUSERLBK */
 	   0,	/* SETINSETTRIGONLY */
 	   0,	/* DZTRIGINTRIG */
-	   0,	/* SECNODZTRIGINTP */
+	   0,	/* UNUSEDMSG1373 */
 	   0,	/* BOOLSIDEFFECT */
 	   0,	/* DBBADUPGRDSTATE */
 	   0,	/* WRITEWAITPID */
@@ -1218,7 +1218,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* JNLORDBFLU */
 	   0,	/* ZCCLNUPRTNMISNG */
 	   0,	/* ZCINVALIDKEYWORD */
-	   0,	/* REPLNOMULTILINETRG */
+	   0,	/* UNUSEDMSG1385 */
 	   0,	/* DBSHMNAMEDIFF */
 	   0,	/* SHMREMOVED */
 	   0,	/* DEVICEWRITEONLY */
@@ -1370,7 +1370,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* ISSPANGBL */
 	   0,	/* TPNOSUPPORT */
 	   0,	/* GVSUBSERR */
-	   0,	/* TRIGNOSPANGBL */
+	   0,	/* UNUSEDMSG1539 */
 	   0,	/* FILTERTIMEDOUT */
 	   0,	/* TLSDLLNOOPEN */
 	   0,	/* TLSINIT */
@@ -1407,4 +1407,19 @@ const static readonly int error_ansi[] = {
 	  13,	/* LABELNOTFND */
 	   0,	/* RELINKCTLERR */
 	   0,	/* INVLINKTMPDIR */
+	   0,	/* NOEDITOR */
+	   0,	/* UPDPROC */
+	   0,	/* HLPPROC */
+	   0,	/* REPLNOHASHTREC */
+	   0,	/* REMOTEDBNOTRIG */
+	   0,	/* NEEDTRIGUPGRD */
+	   0,	/* REQRLNKCTLRNDWN */
+	   0,	/* RLNKCTLRNDWNSUC */
+	   0,	/* RLNKCTLRNDWNFL */
+	   0,	/* MPROFRUNDOWN */
+	   0,	/* ZPEEKNOJNLINFO */
+	   0,	/* TLSPARAM */
+	   0,	/* RLNKRECLATCH */
+	   0,	/* RLNKSHMLATCH */
+	   0,	/* JOBLVN2LONG */
 	};
diff --git a/sr_i386/merrors_ctl.c b/sr_i386/merrors_ctl.c
index 4c4ea08..fc01b83 100644
--- a/sr_i386/merrors_ctl.c
+++ b/sr_i386/merrors_ctl.c
@@ -330,7 +330,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"LDBINFMT", "Unrecognized header for load file", 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,
@@ -413,7 +413,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"JNLBADLABEL", "Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.", 6,
 	"JNLREADEOF", "End of journal file encountered for !AD", 2,
 	"JNLRECFMT", "Journal file record format error encountered", 0,
 	"BLKTOODEEP", "Block level too deep", 0,
@@ -611,7 +611,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"UNUSEDMSG776", "TRIGMODINTP last used in V6.2-000", 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,
@@ -644,7 +644,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
-	"RECLOAD", "Error loading record number: !UL!/", 1,
+	"RECLOAD", "Error loading record number: !@UQ!/", 1,
 	"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,
@@ -733,7 +733,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"RELINKCTLFULL", "Relinkctl file for directory !AD is full (maximum entries !UL)", 3,
 	"UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0,
 	"DBBADNSUB", "!AD Bad numeric subscript", 2,
 	"DBBADKYNM", "!AD Bad key name", 2,
@@ -1202,13 +1202,13 @@ LITDEF	err_msg merrors[] = {
 	"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 at XQ", 7,
 	"TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0,
-	"UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
+	"ZLINKBYPASS", "ZLINK of !AD bypassed - Identical routine already linked", 2,
 	"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 at 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,
+	"UNUSEDMSG1373", "SECNODZTRIGINTP : Last used in V6.2-000", 0,
 	"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,
@@ -1220,7 +1220,7 @@ LITDEF	err_msg merrors[] = {
 	"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 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1,
+	"UNUSEDMSG1385", "REPLNOMULTILINETRG : Last used in V6.2-000", 0,
 	"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,
@@ -1240,7 +1240,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted/upgraded 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,
@@ -1372,7 +1372,7 @@ LITDEF	err_msg merrors[] = {
 	"ISSPANGBL", "Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory", 2,
 	"TPNOSUPPORT", "Operation cannot be performed while inside of a TP transaction", 0,
 	"GVSUBSERR", "Invalid subscripted global name specification in $VIEW() function", 0,
-	"TRIGNOSPANGBL", "Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory", 2,
+	"UNUSEDMSG1539", "TRIGNOSPANBL : Last used in V6.2-000", 0,
 	"FILTERTIMEDOUT", "Replication server timed out attempting to read seqno !16 at XQ from external filter", 1,
 	"TLSDLLNOOPEN", "Failed to load GT.M TLS/SSL library for secure communication", 0,
 	"TLSINIT", "Failed to initialize GT.M TLS/SSL library for secure communication", 0,
@@ -1409,6 +1409,21 @@ LITDEF	err_msg merrors[] = {
 	"LABELNOTFND", "GOTO referenced a label that does not exist", 0,
 	"RELINKCTLERR", "Error with relink control structure for $ZROUTINES directory !AD", 2,
 	"INVLINKTMPDIR", "Value for $gtm_linktmpdir is either not found or not a directory: !AD", 2,
+	"NOEDITOR", "Can't find an executable editor: !AD", 2,
+	"UPDPROC", "Update Process error", 0,
+	"HLPPROC", "Helper Process error", 0,
+	"REPLNOHASHTREC", "Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue", 3,
+	"REMOTEDBNOTRIG", "Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file", 4,
+	"NEEDTRIGUPGRD", "Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first", 2,
+	"REQRLNKCTLRNDWN", "Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown", 2,
+	"RLNKCTLRNDWNSUC", "Relinkctl file for $ZROUTINES directory !AD successfully rundown", 2,
+	"RLNKCTLRNDWNFL", "Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)", 3,
+	"MPROFRUNDOWN", "Error during M-profiling rundown", 0,
+	"ZPEEKNOJNLINFO", "$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled", 2,
+	"TLSPARAM", "TLS parameter !AD !AD", 4,
+	"RLNKRECLATCH", "Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD", 3,
+	"RLNKSHMLATCH", "Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD", 2,
+	"JOBLVN2LONG", "The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL", 2,
 };
 
 LITDEF	int ERR_ACK = 150372361;
@@ -2009,7 +2024,7 @@ 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_UNUSEDMSG776 = 150377146;
 LITDEF	int ERR_BCKUPBUFLUSH = 150377154;
 LITDEF	int ERR_NOFORKCORE = 150377160;
 LITDEF	int ERR_JNLREAD = 150377170;
@@ -2131,7 +2146,7 @@ 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_RELINKCTLFULL = 150378122;
 LITDEF	int ERR_UNUSEDMSG899 = 150378131;
 LITDEF	int ERR_DBBADNSUB = 150378138;
 LITDEF	int ERR_DBBADKYNM = 150378146;
@@ -2600,13 +2615,13 @@ 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_ZLINKBYPASS = 150381875;
 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_UNUSEDMSG1373 = 150381922;
 LITDEF	int ERR_BOOLSIDEFFECT = 150381928;
 LITDEF	int ERR_DBBADUPGRDSTATE = 150381936;
 LITDEF	int ERR_WRITEWAITPID = 150381946;
@@ -2618,7 +2633,7 @@ 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_UNUSEDMSG1385 = 150382018;
 LITDEF	int ERR_DBSHMNAMEDIFF = 150382026;
 LITDEF	int ERR_SHMREMOVED = 150382035;
 LITDEF	int ERR_DEVICEWRITEONLY = 150382042;
@@ -2770,7 +2785,7 @@ LITDEF	int ERR_GBLNOMAPTOREG = 150383202;
 LITDEF	int ERR_ISSPANGBL = 150383210;
 LITDEF	int ERR_TPNOSUPPORT = 150383218;
 LITDEF	int ERR_GVSUBSERR = 150383226;
-LITDEF	int ERR_TRIGNOSPANGBL = 150383234;
+LITDEF	int ERR_UNUSEDMSG1539 = 150383234;
 LITDEF	int ERR_FILTERTIMEDOUT = 150383242;
 LITDEF	int ERR_TLSDLLNOOPEN = 150383250;
 LITDEF	int ERR_TLSINIT = 150383258;
@@ -2807,9 +2822,24 @@ LITDEF	int ERR_CRYPTBADWRTPOS = 150383498;
 LITDEF	int ERR_LABELNOTFND = 150383506;
 LITDEF	int ERR_RELINKCTLERR = 150383514;
 LITDEF	int ERR_INVLINKTMPDIR = 150383522;
+LITDEF	int ERR_NOEDITOR = 150383530;
+LITDEF	int ERR_UPDPROC = 150383538;
+LITDEF	int ERR_HLPPROC = 150383546;
+LITDEF	int ERR_REPLNOHASHTREC = 150383554;
+LITDEF	int ERR_REMOTEDBNOTRIG = 150383562;
+LITDEF	int ERR_NEEDTRIGUPGRD = 150383570;
+LITDEF	int ERR_REQRLNKCTLRNDWN = 150383578;
+LITDEF	int ERR_RLNKCTLRNDWNSUC = 150383587;
+LITDEF	int ERR_RLNKCTLRNDWNFL = 150383594;
+LITDEF	int ERR_MPROFRUNDOWN = 150383602;
+LITDEF	int ERR_ZPEEKNOJNLINFO = 150383610;
+LITDEF	int ERR_TLSPARAM = 150383618;
+LITDEF	int ERR_RLNKRECLATCH = 150383626;
+LITDEF	int ERR_RLNKSHMLATCH = 150383634;
+LITDEF	int ERR_JOBLVN2LONG = 150383642;
 
 GBLDEF	err_ctl merrors_ctl = {
 	246,
 	"GTM",
 	&merrors[0],
-	1396};
+	1411};
diff --git a/sr_i386/obj_file.c b/sr_i386/obj_file.c
index 6072f3c..ab858b3 100644
--- a/sr_i386/obj_file.c
+++ b/sr_i386/obj_file.c
@@ -44,6 +44,7 @@ GBLREF mident		module_name;
 GBLREF boolean_t	run_time;
 GBLREF int4		mlmax, mvmax;
 GBLREF int4		code_size, lit_addrs, lits_size;
+GBLREF spdesc		stringpool;
 
 GBLDEF int4	psect_use_tab[GTM_LASTPSECT];	/* bytes of each psect in this module */
 GBLREF char	object_file_name[];
@@ -58,7 +59,8 @@ 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;)
+static struct sym_table *symbols;
+DEBUG_ONLY(static uint4 txtrel_cnt_in_hdr;)
 
 error_def(ERR_OBJFILERR);
 error_def(ERR_STRINGOFLOW);
@@ -68,10 +70,8 @@ void create_object_file(rhdtyp *rhead)
 	struct exec	hdr;
 
 	assert(!run_time);
-
 	init_object_file_name(); /* inputs: cmd_qlf.object_file, module_name; outputs: object_file_name, object_name_len */
 	object_file_des = mk_tmp_object_file(object_file_name, object_name_len);
-
 	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);
@@ -79,7 +79,6 @@ void create_object_file(rhdtyp *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;
@@ -96,7 +95,7 @@ void create_object_file(rhdtyp *rhead)
 	emit_immed((char *)rhead, SIZEOF(*rhead));
 }
 
-void close_object_file(void)
+void finish_object_file(void)
 {
 	assert(0 == PADLEN(lits_size, NATIVE_WSIZE));
 	resolve_sym();
@@ -108,7 +107,6 @@ void close_object_file(void)
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
 }
 
-
 void drop_object_file(void)
 {
 	int	rc;
@@ -120,8 +118,6 @@ void drop_object_file(void)
         }
 }
 
-GBLREF spdesc stringpool;
-
 void emit_addr(int4 refaddr, int4 offset, int4 *result)
 {
 	struct rel_table *newrel;
@@ -152,7 +148,6 @@ void emit_addr(int4 refaddr, int4 offset, int4 *result)
 	return;
 }
 
-
 void emit_pidr(int4 refoffset, int4 data_offset, int4 *result)
 {
 	struct rel_table *newrel;
@@ -178,7 +173,6 @@ void emit_pidr(int4 refoffset, int4 data_offset, int4 *result)
 	}
 }
 
-
 void emit_reference(uint4 refaddr, mstr *name, uint4 *result)
 {
 	struct sym_table *sym;
@@ -212,13 +206,11 @@ void emit_reference(uint4 refaddr, mstr *name, uint4 *result)
 	}
 }
 
-
 /*
  *	emit_immed
  *
  *	Args:  buffer of executable code, and byte count to be output.
  */
-
 void emit_immed(char *source, uint4 size)
 {
 	short int write;
@@ -245,13 +237,11 @@ void emit_immed(char *source, uint4 size)
 	}
 }
 
-
 /*
  *	buff_emit
  *
  *	Args:  buffer pointer, number of bytes to emit
  */
-
 void buff_emit(void)
 {
 	uint4 stat;
@@ -261,7 +251,6 @@ void buff_emit(void)
 	emit_buff_used = 0;
 }
 
-
 void set_psect(unsigned char psect,unsigned char offset)
 {
 	current_psect = psect;
@@ -276,8 +265,6 @@ void set_psect(unsigned char psect,unsigned char offset)
  *	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;
@@ -341,7 +328,6 @@ void resolve_sym(void)
 	}
 }
 
-
 void output_relocation(void)
 {
 	struct rel_table 	*rel;
@@ -368,7 +354,6 @@ void output_relocation(void)
 	assert(cnt == lit_addrs);
 }
 
-
 void output_symbol(void)
 {
 	uint4 string_length;
@@ -392,7 +377,6 @@ void output_symbol(void)
 	}
 }
 
-
 void obj_init(void)
 {
 	cdlits = txtrel_cnt = 0;
@@ -400,8 +384,6 @@ void obj_init(void)
 	symbols = 0;
 }
 
-
-
 void emit_literals(void)
 {
 	uint4 offset, padsize;
diff --git a/sr_linux/hugetlbfs_overrides.h b/sr_linux/hugetlbfs_overrides.h
deleted file mode 100644
index f212773..0000000
--- a/sr_linux/hugetlbfs_overrides.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/****************************************************************
- *								*
- *	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_ */
diff --git a/sr_linux/release_name.h b/sr_linux/release_name.h
index d67cbe3..051fb77 100644
--- a/sr_linux/release_name.h
+++ b/sr_linux/release_name.h
@@ -10,15 +10,15 @@
  ****************************************************************/
 
 #ifdef __CYGWIN__
-#define GTM_RELEASE_NAME 	"GT.M V6.2-000 CYGWIN x86"
+#define GTM_RELEASE_NAME 	"GT.M V6.2-001 CYGWIN x86"
 #elif defined(__ia64)
-#define GTM_RELEASE_NAME 	"GT.M V6.2-000 Linux IA64"
+#define GTM_RELEASE_NAME 	"GT.M V6.2-001 Linux IA64"
 #elif defined(__x86_64__)
-#define GTM_RELEASE_NAME 	"GT.M V6.2-000 Linux x86_64"
+#define GTM_RELEASE_NAME 	"GT.M V6.2-001 Linux x86_64"
 #elif defined(__s390__)
-#define GTM_RELEASE_NAME 	"GT.M V6.2-000 Linux S390X"
+#define GTM_RELEASE_NAME 	"GT.M V6.2-001 Linux S390X"
 #else
-#define GTM_RELEASE_NAME 	"GT.M V6.2-000 Linux x86"
+#define GTM_RELEASE_NAME 	"GT.M V6.2-001 Linux x86"
 #endif
 #define GTM_PRODUCT 		"GT.M"
 #define GTM_VERSION		"V6.2"
diff --git a/sr_port/advancewindow.c b/sr_port/advancewindow.c
index 39b12d0..802a1cc 100644
--- a/sr_port/advancewindow.c
+++ b/sr_port/advancewindow.c
@@ -26,7 +26,7 @@
 #endif
 
 GBLREF	unsigned char	*source_buffer;
-GBLREF	short int	source_column;
+GBLREF	int		source_column;
 GBLREF	char		*lexical_ptr;
 GBLREF	spdesc		stringpool;
 GBLREF	boolean_t	gtm_utf8_mode;
@@ -76,14 +76,15 @@ void advancewindow(void)
 		TREF(director_token) = TK_EOL;
 		return;		/* if next character is terminator, avoid incrementing past it */
 	case TK_QUOTE:
-		ENSURE_STP_FREE_SPACE(MAX_SRCLINE);
+		ENSURE_STP_FREE_SPACE(TREF(max_advancewindow_line));
 		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);
+				cptr = (unsigned char *)UTF8_MBTOWC((sm_uc_ptr_t)cp1, source_buffer + TREF(max_advancewindow_line),
+								    ch);
 #			endif
 			x = *cp1++;
 			if ((SP > x) UNICODE_ONLY(|| (gtm_utf8_mode && !(U_ISPRINT(ch)))))
@@ -178,7 +179,7 @@ void advancewindow(void)
 			break;
 	case TK_DIGIT:
 		(TREF(director_mval)).str.addr = lexical_ptr;
-		(TREF(director_mval)).str.len = MAX_SRCLINE;
+		(TREF(director_mval)).str.len = TREF(max_advancewindow_line);
 		(TREF(director_mval)).mvtype = MV_STR;
 		lexical_ptr = (char *)s2n(&(TREF(director_mval)));
 		if (!((TREF(director_mval)).mvtype &= MV_NUM_MASK))
@@ -293,6 +294,9 @@ void advancewindow(void)
  *
  * 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.
+ *
+ * Update: Like '#', we need to allow '/' as well to allow for an overriding region name to be specified (where the
+ * trigger needs to be searched. So handle that as well in this same function.
  */
 void advwindw_hash_in_mname_allowed(void)
 {
@@ -310,9 +314,9 @@ void advwindw_hash_in_mname_allowed(void)
 	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 '#' */
+	/* Start processing with the token following the '#'. Allow '#' and/or '/' in addition to usual stuff. */
 	for (x = *lexical_ptr, ch = ctypetab[x];
-	     ((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch));
+	     ((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch) || (TK_SLASH == ch));
 	     x = *++lexical_ptr, ch = ctypetab[x])
 	{
 		if (cp2 < cp3)
diff --git a/sr_port/buddy_list.c b/sr_port/buddy_list.c
index d2ca856..6eb3d23 100644
--- a/sr_port/buddy_list.c
+++ b/sr_port/buddy_list.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -183,7 +183,8 @@ char    *find_element(buddy_list *list, int4 index)
         if (index > list->nElems)
                 return NULL;
 	initAllocBits = list->initAllocBits;
-	for (i = initAllocBits; index >> i; i++);
+	for (i = initAllocBits; index >> i; i++)	/* not sure if "ceil_log2_32bit" would be faster here */
+		;
 	i = i - initAllocBits;
 	return list->ptrArray[i] + list->elemSize * (index - list->initAlloc * (i ? 1 << (i-1) : 0));
 }
diff --git a/sr_port/ceil_log2.c b/sr_port/ceil_log2.c
new file mode 100644
index 0000000..c94e213
--- /dev/null
+++ b/sr_port/ceil_log2.c
@@ -0,0 +1,77 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made available	*
+ *	under a license.  If you do not know the terms of	*
+ *	the license, please stop and do not read further.	*
+ *								*
+ ****************************************************************/
+#include "mdef.h"
+
+/* ceil_log2_table[i] = # of bits needed to represent i */
+static int	ceil_log2_table[] = { 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
+
+/* Compute the ceiling(log_2(num)) where num is a 64-bit quantity */
+int ceil_log2_64bit(gtm_uint64_t num)
+{
+	int		ret;
+
+	assert(num);
+	num--;
+	ret = 0;
+	if (((gtm_uint64_t)1 << 32) <= num)
+	{
+		ret += 32;
+		num = num >> 32;
+	}
+	if ((1 << 16) <= num)
+	{
+		ret += 16;
+		num = num >> 16;
+	}
+	if ((1 << 8) <= num)
+	{
+		ret += 8;
+		num = num >> 8;
+	}
+	if ((1 << 4) <= num)
+	{
+		ret += 4;
+		num = num >> 4;
+	}
+	assert(ARRAYSIZE(ceil_log2_table) > num);
+	/* Now that "num" is a small number, use lookup table to speed up computation */
+	ret += ceil_log2_table[num];
+	return ret;
+}
+
+/* Compute the ceiling(log_2(num)) where num is a 32-bit quantity */
+int ceil_log2_32bit(uint4 num)
+{
+	int		ret;
+
+	assert(num);
+	num--;
+	ret = 0;
+	if ((1 << 16) <= num)
+	{
+		ret += 16;
+		num = num >> 16;
+	}
+	if ((1 << 8) <= num)
+	{
+		ret += 8;
+		num = num >> 8;
+	}
+	if ((1 << 4) <= num)
+	{
+		ret += 4;
+		num = num >> 4;
+	}
+	assert(ARRAYSIZE(ceil_log2_table) > num);
+	/* Now that "num" is a small number, use lookup table to speed up computation */
+	ret += ceil_log2_table[num];
+	return ret;
+}
diff --git a/sr_port/cmd.c b/sr_port/cmd.c
index 823d70f..0802dde 100644
--- a/sr_port/cmd.c
+++ b/sr_port/cmd.c
@@ -52,7 +52,7 @@ int cmd(void)
 	 * One for full command and one for short-hand notation.
 	 * For example, B and and BREAK.
 	 */
-LITDEF nametabent cmd_names[] =
+	LITDEF nametabent cmd_names[] =
 	{
 		{1, "B"}, {5, "BREAK"}
 		,{1, "C"}, {5, "CLOSE"}
@@ -97,7 +97,7 @@ LITDEF nametabent cmd_names[] =
 		,{2, "ZL"}, {5, "ZLINK"}
 		,{2, "ZM"}, {8, "ZMESSAGE"}
 		,{2, "ZP"}, {6, "ZPRINT"}
-#		ifdef USHBIN_SUPPORTED
+#		ifdef AUTORELINK_SUPPORTED
 		,{3, "ZRU"}, {8, "ZRUPDATE"}
 #		endif
 		,{3, "ZSH"}, {5, "ZSHOW"}
@@ -134,7 +134,7 @@ 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, 94 GTMTRIG_ONLY(+ 2) USHBIN_ONLY(+ 2) /* add ztrigger and zrupdate, respectively */
+		,51, 51, 94 GTMTRIG_ONLY(+ 2) ARLINK_ONLY(+ 2) /* add ztrigger and zrupdate, respectively */
 	};
 LITDEF struct
 	{
@@ -189,7 +189,7 @@ LITDEF struct
 		,{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}
-#		ifdef USHBIN_SUPPORTED
+#		ifdef AUTORELINK_SUPPORTED
 		,{m_zrupdate, 0, 1, ALL_SYS}, {m_zrupdate, 0, 1, ALL_SYS}
 #		endif
 		,{m_zshow, 1, 1, ALL_SYS}, {m_zshow, 1, 1, ALL_SYS}
diff --git a/sr_port/code_gen.c b/sr_port/code_gen.c
index 8df4b9f..5902588 100644
--- a/sr_port/code_gen.c
+++ b/sr_port/code_gen.c
@@ -29,7 +29,8 @@ 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	short		source_line;
+GBLREF int		source_column;
 GBLREF	int4		pending_errtriplecode;	/* if non-zero contains the error code to invoke ins_errtriple with */
 
 void	code_gen(void)
diff --git a/sr_port/comp_fini.c b/sr_port/comp_fini.c
index 61c108b..724afde 100644
--- a/sr_port/comp_fini.c
+++ b/sr_port/comp_fini.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -28,7 +28,7 @@
  *	rts_stringpool to indr_stringpool during compilation setup.
  */
 GBLREF spdesc		stringpool, rts_stringpool, indr_stringpool;
-GBLREF short int	source_column;
+GBLREF int		source_column;
 GBLREF char		cg_phase;
 GBLREF unsigned char	*source_buffer;
 
diff --git a/sr_port/comp_init.c b/sr_port/comp_init.c
index 0864ba7..c9788e5 100644
--- a/sr_port/comp_init.c
+++ b/sr_port/comp_init.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -40,8 +40,8 @@ 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);
+	if ((unsigned)src->len >= TREF(max_advancewindow_line))
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INDRMAXLEN, 1, TREF(max_advancewindow_line));
 	memcpy(source_buffer,src->addr,src->len);
 	source_buffer[src->len + 1] = source_buffer[src->len] = 0;
 	TREF(compile_time) = TRUE;
@@ -57,6 +57,7 @@ void comp_init(mstr *src, oprtype *dst)
 		indr_stringpool = stringpool;
 	} else
 		stringpool = indr_stringpool;
+	mcfree();
 	tripinit();
 	lb_init();
 	assert(TREF(for_stack_ptr) == TADR(for_stack));
diff --git a/sr_port/compile_pattern.c b/sr_port/compile_pattern.c
index 7904f07..2b6d9dc 100644
--- a/sr_port/compile_pattern.c
+++ b/sr_port/compile_pattern.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -24,7 +24,7 @@
 GBLREF spdesc		stringpool;
 GBLREF char		*lexical_ptr;
 GBLREF unsigned char	*source_buffer;
-GBLREF short int	source_column;
+GBLREF int		source_column;
 
 int compile_pattern(oprtype *opr, boolean_t is_indirect)
 {
@@ -70,6 +70,7 @@ int compile_pattern(oprtype *opr, boolean_t is_indirect)
 			stx_error(status);
 			return FALSE;
 		}
+		memset(&retmval, 0, SIZEOF(mval));
 		retmval.mvtype = MV_STR;
 		retmval.str.len = retstr.len * SIZEOF(uint4);
 		retmval.str.addr = (char *)stringpool.free;
diff --git a/sr_port/compiler_startup.c b/sr_port/compiler_startup.c
index 732782e..73c9ba3 100644
--- a/sr_port/compiler_startup.c
+++ b/sr_port/compiler_startup.c
@@ -33,7 +33,8 @@
 
 #define HOPELESS_COMPILE 128
 
-GBLREF short int source_column, source_line;
+GBLREF short int source_line;
+GBLREF int	source_column;
 
 GBLREF unsigned char		source_file_name[];
 GBLREF unsigned char 		*source_buffer;
diff --git a/sr_port/db_auto_upgrade.c b/sr_port/db_auto_upgrade.c
index 99dde60..d088d12 100644
--- a/sr_port/db_auto_upgrade.c
+++ b/sr_port/db_auto_upgrade.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -132,8 +132,11 @@ void db_auto_upgrade(gd_region *reg)
 			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:
+				/* GT.M V62001 introduced ^#t upgrade. Record this pending event in filehdr. */
+				UNIX_ONLY(csd->hasht_upgrade_needed = TRUE;)
+				break;
+			case GDSMV62001:
 				/* 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. */
@@ -149,7 +152,7 @@ void db_auto_upgrade(gd_region *reg)
                  */
 		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));
+		send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_DBBADUPGRDSTATE, 4, REG_LEN_STR(reg), DB_LEN_STR(reg));
 	}
 	return;
 }
diff --git a/sr_port/db_csh_getn.c b/sr_port/db_csh_getn.c
index 00d9fb3..3f37e7a 100644
--- a/sr_port/db_csh_getn.c
+++ b/sr_port/db_csh_getn.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -75,10 +75,10 @@ error_def(ERR_INVALIDRIP);
 
 cache_rec_ptr_t	db_csh_getn(block_id block)
 {
-	cache_rec_ptr_t		hdr, q0, start_cr, cr;
+	cache_rec_ptr_t		cr, hdr, midnite, our_midnite, q0, start_cr;
 	bt_rec_ptr_t		bt;
 	unsigned int		lcnt, ocnt;
-	int			rip, max_ent, pass1, pass2, pass3;
+	int			max_ent, pass0, pass0cnt, pass1, pass2, pass3, rip;
 	int4			flsh_trigger;
 	uint4			first_r_epid, latest_r_epid;
 	sgmnt_addrs		*csa;
@@ -95,15 +95,27 @@ cache_rec_ptr_t	db_csh_getn(block_id block)
 	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)
-	);
+	pass0 = csa->gbuff_limit;		/* gbuff_limit set by VIEW "POOLLIMIT":<region> */
+	pass0cnt = (0 == pass0) ? 0 : 2;	/* used both as a flag we are limiting and a counter for 2 limited trips */
+	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 */
+	midnite = start_cr + max_ent;		/* "on the clock" - point at which we have to wrap or change tactics */
+	cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off);
+	if (pass0cnt)
+	{
+		our_midnite = csa->our_midnite;		/* local copy of private "hand" for efficiency - only used if pass0cnt */
+		cr = our_midnite - pass0;		/* direct this process to an area behind our chosen spot */
+		if (cr < start_cr)
+			cr += max_ent;			/* we have to wrap before we use our_midnite */
+		else
+			midnite = our_midnite;
+	}
+	assert((start_cr <= cr) && ((start_cr + max_ent) > cr));
+	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++)
@@ -115,8 +127,36 @@ cache_rec_ptr_t	db_csh_getn(block_id block)
 			break;
 		}
 		cr++;
-		if (cr == start_cr + max_ent)
+		if (cr == midnite)
+		{
 			cr = start_cr;
+			if (pass0cnt)
+			{	/* doing restricted looking */
+				if (midnite != our_midnite)
+				{	/* "ordinary" end of buffer - wrap and set up private stop */
+					assert((start_cr + max_ent) == midnite);
+					midnite = our_midnite;
+				} else
+				{	/* the end of our restricted area */
+					if (--pass0cnt)
+					{	/* if limiting and in pass0, do a 2nd scan of the limit area */
+						cr = our_midnite - pass0;		/* in our restricted area */
+						if (cr < start_cr)
+						{	/* wrap before our_midnite */
+							cr += max_ent;
+							midnite = start_cr + max_ent;
+						}
+					} else
+					{	/* or the limited area did not suffice - adopt the normal clock */
+						cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off);
+						midnite = start_cr + max_ent;
+					}
+					assert((pass0cnt + lcnt) == pass0);
+					lcnt = 0;
+				}
+			}
+		}
+		assert((start_cr <= cr) && ((start_cr + max_ent) > cr));
 		VMS_ONLY(
 			if ((lcnt == pass1) || (lcnt == pass2))
 				wcs_wtfini(gv_cur_region);
@@ -266,7 +306,7 @@ cache_rec_ptr_t	db_csh_getn(block_id block)
 				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));
+					send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(gv_cur_region));
 					assert(cr->r_epid == 0);
 					cr->r_epid = 0;
 					INTERLOCK_INIT(cr);
@@ -295,12 +335,11 @@ cache_rec_ptr_t	db_csh_getn(block_id block)
 				BG_TRACE_PRO(db_csh_getn_buf_owner_stuck);
 				if (0 != latest_r_epid)
 				{
-					if (first_r_epid != latest_r_epid)
-						GTMASSERT;
+					assertpro(first_r_epid == latest_r_epid);
 					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,
+					send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id,
 						 cr->blk, cr, first_r_epid, DB_LEN_STR(gv_cur_region));
 					continue;
 				}
@@ -348,7 +387,8 @@ cache_rec_ptr_t	db_csh_getn(block_id block)
 		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 (!pass0cnt)
+			csa->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cr);
 		if (lcnt > pass1)
 			csa->nl->cache_hits = 0;
 		csa->nl->cache_hits++;
diff --git a/sr_port/dbcertify_certify_phase.c b/sr_port/dbcertify_certify_phase.c
index 2dc32e7..dbe0c9b 100644
--- a/sr_port/dbcertify_certify_phase.c
+++ b/sr_port/dbcertify_certify_phase.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -149,11 +149,11 @@ void dbcertify_certify_phase(void)
 	{
 		save_errno = errno;
 		if (save_errno == ENOENT)
-			rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn));
+			rts_error_csa(CSA_ARG(NULL) 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),
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn),
 				  ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
 		}
 	}
@@ -163,10 +163,10 @@ void dbcertify_certify_phase(void)
 #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));
+		rts_error_csa(CSA_ARG(NULL) 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));
+		rts_error_csa(CSA_ARG(NULL) 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 */
@@ -207,9 +207,9 @@ void dbcertify_certify_phase(void)
 	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);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB);
 	if (psa->ofhdr.tn > psa->dbc_cs_data->trans_hist.curr_tn)
-		rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB);
+		rts_error_csa(CSA_ARG(NULL) 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 */
@@ -265,7 +265,7 @@ void dbcertify_certify_phase(void)
 				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? */
+						assertpro(FALSE);		/* 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 */
@@ -278,7 +278,7 @@ void dbcertify_certify_phase(void)
 		{
 			++restart_cnt;
 			if (MAX_RESTART_CNT < restart_cnt)
-				GTMASSERT;			/* No idea what could cause this.. */
+				assertpro(FALSE);			/* 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 */
@@ -302,14 +302,14 @@ void dbcertify_certify_phase(void)
 		{
 			((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"));
+			gtm_putmsg_csa(CSA_ARG(NULL) 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));
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCDBNOCERTIFY, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn));
 
 	dbc_flush_fhead(psa);
 	dbc_close_db(psa);
@@ -351,6 +351,8 @@ void dbcertify_certify_phase(void)
 	if (psa->first_rec_key)
 		free(psa->first_rec_key);
 	free(psa);
+	assert(psa == psa_gbl);
+	psa_gbl = NULL;	/* nullify the global variable now that it has been freed */
 }
 
 /* Routine to handle the processing (splitting) of a given database block. If the current block process needs
@@ -473,7 +475,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 		   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);
+		rts_error_csa(CSA_ARG(NULL) 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);
@@ -524,9 +526,9 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			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"));
+				rts_error_csa(CSA_ARG(NULL) 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:
@@ -536,8 +538,9 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			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"));
+				rts_error_csa(CSA_ARG(NULL) 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
@@ -559,7 +562,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					if (-1 == blk_index)
 					{	/* Integrity error encountered. We cannot proceed */
 						assert(FALSE);
-						rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2,
+						rts_error_csa(CSA_ARG(NULL) 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"));
@@ -584,7 +587,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 						}
 						return FALSE;	/* No restart necessary */
 					} else
-						GTMASSERT;
+						assertpro(FALSE);
 				}
 			} else
 			{	/* This is a gvtroot block and is the subject of our search */
@@ -593,7 +596,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			}
 			break;
 		default:
-			GTMASSERT;
+			assertpro(FALSE);
 	}
 	/* 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,
@@ -602,7 +605,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 	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),
+		rts_error_csa(CSA_ARG(NULL) 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"));
 	}
@@ -846,7 +849,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 				blk_set_p->curr_rec + remain_offset,
 				remain_len - remain_offset);
 			if (0 == BLK_FINI(bs_ptr, bs1))
-				GTMASSERT;
+				assertpro(FALSE);
 			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;
@@ -912,7 +915,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			/* Common initialization */
 			++psa->block_depth;			/* Need a new block to split into */
 			if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth)
-				GTMASSERT;
+				assertpro(FALSE);
 			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);
@@ -944,7 +947,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 						 * it by NOT certifying the database and requiring a rerun of the SCAN
 						 */
 						assert(FALSE);
-						gtm_putmsg(VARLSTCNT(6) ERR_DBCREC2BIGINBLK, 4,
+						gtm_putmsg_csa(CSA_ARG(NULL) 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);
@@ -970,7 +973,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 				}
 				/* Complete our LHS block */
 				if (0 == BLK_FINI(bs_ptr, bs1))
-					GTMASSERT;
+					assertpro(FALSE);
 				assert(blk_seg_cnt == new_lh_blk_len);
 				/* Remember key of last record in this block */
 				if (0 == ins_rec_len)
@@ -1006,7 +1009,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					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;
+						assertpro(FALSE);
 					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
@@ -1037,7 +1040,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					curr_blk_len - curr_rec_offset - SIZEOF(rec_hdr));
 				/* Complete update array */
 				if (0 == BLK_FINI(bs_ptr, bs1))
-					GTMASSERT;
+					assertpro(FALSE);
 				assert(blk_seg_cnt == new_rh_blk_len);
 			} else
 			{	/* Recompute sizes for inserted record being in righthand block as per
@@ -1071,7 +1074,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					*/
 					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_csa(CSA_ARG(NULL) 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
@@ -1084,7 +1087,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					     ++restart_cnt)
 					{
 						if (MAX_RESTART_CNT < restart_cnt)
-							GTMASSERT;		/* No idea what could cause this */
+							assertpro(FALSE);		/* 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 */
@@ -1116,7 +1119,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 				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;
+					assertpro(FALSE);
 				assert(blk_seg_cnt == new_lh_blk_len);
 				if (!got_root)
 				{
@@ -1148,7 +1151,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					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;
+						assertpro(FALSE);
 					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;
@@ -1191,7 +1194,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 					blk_set_p->curr_rec + remain_offset,
 					remain_len - remain_offset);
 				if (0 == BLK_FINI(bs_ptr, bs1))
-					GTMASSERT;
+					assertpro(FALSE);
 				assert(blk_seg_cnt == new_rh_blk_len);
 			} /* else method (2) */
 			if (got_root)
@@ -1207,7 +1210,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 				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;
+					assertpro(FALSE);
 				/* 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);
@@ -1227,7 +1230,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 				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;
+					assertpro(FALSE);
 				/* 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;
@@ -1272,7 +1275,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 		*/
 		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));
+			rts_error_csa(CSA_ARG(NULL) 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.
 		*/
@@ -1306,8 +1309,8 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			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);
+				rts_error_csa(CSA_ARG(NULL) 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;
@@ -1328,8 +1331,8 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 			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);
+				rts_error_csa(CSA_ARG(NULL) 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
@@ -1437,7 +1440,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty
 		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 */
+		assertpro(FALSE);	/* 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++;
 
@@ -1470,7 +1473,7 @@ void dbc_read_p1out(phase_static_area *psa, void *obuf, int olen)
 		save_errno = errno;
 		errmsg = STRERROR(save_errno);
 		assert(FALSE);
-		rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("read()"), CALLFROM,
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("read()"), CALLFROM,
 			  ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
 	}
 }
@@ -1481,12 +1484,14 @@ void dbc_certify_phase_cleanup(void)
 	phase_static_area	*psa;
 
 	psa = psa_gbl;
+	if (NULL == psa)
+		return;
 	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,
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT,
 				  2, RTS_ERROR_LITERAL("Failure while in critical section -- database damage likely"));
 	}
 	UNIX_ONLY(dbc_release_standalone_access(psa));
diff --git a/sr_port/dbcertify_scan_phase.c b/sr_port/dbcertify_scan_phase.c
index ba74a7c..ef495f2 100644
--- a/sr_port/dbcertify_scan_phase.c
+++ b/sr_port/dbcertify_scan_phase.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -420,6 +420,8 @@ void dbcertify_scan_phase(void)
 		psa->iebl = iebl;
 	}
 	free(psa);
+	assert(psa == psa_gbl);
+	psa_gbl = NULL;	/* nullify the global variable now that it has been freed */
 }
 
 /* Write the given output record but keep the global variable "chksum" updated with the tally.
@@ -853,16 +855,21 @@ uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t trec_p)
 /* Simple cleanup routine for this scan phaase */
 void dbc_scan_phase_cleanup(void)
 {
+	phase_static_area	*psa;
+
+	psa = psa_gbl;
+	if (NULL == psa)
+		return;
 	/* Cleanup our temporary files */
-	if (psa_gbl->tmp_file_names_gend)
+	if (psa->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);
+		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);
 	}
 }
diff --git a/sr_port/dse.hlp b/sr_port/dse.hlp
index 3b0c3c1..c586487 100644
--- a/sr_port/dse.hlp
+++ b/sr_port/dse.hlp
@@ -244,19 +244,15 @@
    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                     |
@@ -1216,7 +1212,6 @@
 
    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.
@@ -1233,7 +1228,6 @@
    DSE> CACHE -SHOW
    File    /home/jdoe/node1/areg.dat
    Region  AREG
-
    Region AREG : Shared_memory       = 0x00002B6845040000
    Region AREG :  node_local         = 0x0000000000000000
    Region AREG :  critical           = 0x0000000000010000
@@ -1248,7 +1242,6 @@
    Region AREG :  th_base            = 0x00000000002C71D0
    Region AREG :  bt_record          = 0x00000000002C7200 : Numelems = 0x00000400 : Elemsize = 0x00000040
    Region AREG :  shared_memory_size = 0x00000000002D8000
-
    DSE>
 
 2 CLose
@@ -1499,7 +1492,6 @@
 
    File    /home/jdoe/.fis-gtm/V6.1-000_x86_64/g/gtm.dat
    Region  DEFAULT
-
    File            /home/jdoe/.fis-gtm/V6.1-000_x86_64/g/gtm.dat
    Region          DEFAULT
    Date/Time       27-JAN-2014 03:13:40 [$H = 63214,11620]
@@ -1589,7 +1581,6 @@
    Example:
 
    DSE> evaluate -number=10 -decimal
-
    Hex:  A   Dec:  10
 
    This command displays the hexadecimal equivalent of decimal number 10.
@@ -1597,7 +1588,6 @@
    Example:
 
    DSE> evaluate -number=10 -hexadecimal
-
    Hex:  10   Dec:  16
 
    This command displays the decimal equivalent of hexadecimal 10.
@@ -1605,7 +1595,6 @@
    Example:
 
    $ dse evaluate -number=10
-
    Hex:  10   Dec:  16
 
    This command displays the decimal equivalent of Hexadecimal 10. Note that
@@ -1759,7 +1748,6 @@
    Directory path
    Path--blk:off
    1:10 2:1E
-
    Global paths
    Path--blk:off
    6:51 1A4:249 180
@@ -1772,7 +1760,6 @@
    Example:
 
    DSE> find -free -hint=180
-
    Next free block is D8F.
 
    This command locates the "closest" free block to block 180.
@@ -1947,7 +1934,6 @@
    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
@@ -1961,7 +1947,6 @@
    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.......  ........  ........  ........  |
@@ -1979,7 +1964,6 @@
    Block      1A0: |  ........  ........  ........  ........  |
    Block      1C0: |  ........  ........  ........  ........  |
    Block      1E0: |  ........  ........  ........  ........  |
-
    'X' == BUSY  '.' == FREE  ':' == REUSABLE  '?' == CORRUPT
 
    Note that the BLOCK 20 is marked as BUSY.
@@ -2009,7 +1993,6 @@
    Example:
 
    DSE> OPEN
-
    Current output file:  var.out
 
    This command displays the current output file. In this case, the output
@@ -2176,7 +2159,6 @@
    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
@@ -2184,7 +2166,6 @@
    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).
@@ -2845,15 +2826,16 @@
 
    Copyright 2014
 
-   Fidelity Information Services, Inc. All rights reserved.
+   Fidelity National Information Services, Inc. and/or its subsidiaries. All
+   rights reserved.
 
    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or any
    later version published by the Free Software Foundation; with no Invariant
    Sections, no Front-Cover Texts and no Back-Cover Texts.
 
-   GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
-   trademarks are the property of their respective owners.
+   GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+   Other trademarks are the property of their respective owners.
 
    This document contains a description of GT.M and the operating
    instructions pertaining to the various functions that comprise the system.
@@ -2864,7 +2846,7 @@
 
    **Note**
 
-   This help file is a concise representation of revision V6.2-000 of the
+   This help file is a concise representation of revision V6.2-001 of the
    UNIX Administration and Operations Guide. To obtain a copy of the current
    revision, go to www.fis-gtm.com and then click on the User Documentation
    tab.
diff --git a/sr_port/dse_adrec.c b/sr_port/dse_adrec.c
index 0e55bcf..ec0ad4e 100644
--- a/sr_port/dse_adrec.c
+++ b/sr_port/dse_adrec.c
@@ -126,11 +126,11 @@ void dse_adrec(void)
 			free(lbp);
 			return;
 		}
-		if (key_len + data_len >  csa->hdr->max_rec_size)
+		if (VMS_ONLY(key_len + ) data_len >  csa->hdr->max_rec_size)
 		{
 			t_abort(gv_cur_region, csa);
 			free(lbp);
-			rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_REC2BIG, 4, key_len + data_len,
+ 			rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(key_len + ) data_len,
 				(int4)csa->hdr->max_rec_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, LEN_AND_STR(key));
 		}
 	}
diff --git a/sr_port/dse_chng_fhead.c b/sr_port/dse_chng_fhead.c
index 1eaf09d..69c146a 100644
--- a/sr_port/dse_chng_fhead.c
+++ b/sr_port/dse_chng_fhead.c
@@ -572,14 +572,7 @@ void dse_chng_fhead(void)
 			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);
-	}
+		CLRGVSTATS(cs_addrs);
 	if (CLI_PRESENT == cli_present("ONLINE_NBB"))
 	{
 		buf_len = SIZEOF(buf);
diff --git a/sr_port/dse_getki.c b/sr_port/dse_getki.c
index c5d5ff3..230bc72 100644
--- a/sr_port/dse_getki.c
+++ b/sr_port/dse_getki.c
@@ -44,8 +44,6 @@ GBLREF	sgmnt_addrs	*cs_addrs;
 GBLREF	gd_region	*gv_cur_region;
 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];
diff --git a/sr_port/dump_record.c b/sr_port/dump_record.c
index 5a09882..e67f80d 100644
--- a/sr_port/dump_record.c
+++ b/sr_port/dump_record.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -52,8 +52,6 @@ GBLREF int              patch_fdmp_recs;
 GBLREF gd_region    	*gv_cur_region;
 GBLREF gv_namehead	*gv_target;
 
-LITREF	mval		literal_hasht;
-
 #define MAX_UTIL_LEN		80
 #define	NUM_BYTES_PER_LINE	20
 
diff --git a/sr_port/entryref.c b/sr_port/entryref.c
index e32b866..cd1d8cd 100644
--- a/sr_port/entryref.c
+++ b/sr_port/entryref.c
@@ -238,7 +238,7 @@ triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_comma
 	return rettrip;
 }
 
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 /* Routine used in a USHBIN build (UNIX Shared BInary) to generate the triples to reference (call, extrinsic or goto)
  * an external routine. This version calls additional opcodes to dynamically autorelink routines if the routine has been
  * changed since it was last linked if autorelinking is enabled. This requires that all such M-calls with a routine specified
diff --git a/sr_port/error.h b/sr_port/error.h
index d107bdf..8559143 100644
--- a/sr_port/error.h
+++ b/sr_port/error.h
@@ -102,9 +102,11 @@ CONDITION_HANDLER(iomt_ch);
 CONDITION_HANDLER(jnl_file_autoswitch_ch);
 CONDITION_HANDLER(job_init_ch);
 CONDITION_HANDLER(jobexam_dump_ch);
+#ifdef VMS
 CONDITION_HANDLER(lastchance1);
 CONDITION_HANDLER(lastchance2);
 CONDITION_HANDLER(lastchance3);
+#endif
 CONDITION_HANDLER(mdb_condition_handler);
 CONDITION_HANDLER(mu_freeze_ch);
 CONDITION_HANDLER(mu_int_ch);
diff --git a/sr_port/exfunc.c b/sr_port/exfunc.c
index 520aa0d..8ea8fc9 100644
--- a/sr_port/exfunc.c
+++ b/sr_port/exfunc.c
@@ -58,7 +58,7 @@ int exfunc(oprtype *a, boolean_t alias_target)
 		{
 			if (OC_CDLIT == calltrip_opr1_tref->opcode)
 				assert(CDLT_REF == calltrip_opr1_tref->operand[0].oprclass);
-			else USHBIN_ONLY(if (OC_LAB_EXT != calltrip_opr1_tref->opcode))
+			else ARLINK_ONLY(if (OC_LAB_EXT != calltrip_opr1_tref->opcode))
 			{
 				assert(OC_LABADDR == calltrip_opr1_tref->opcode);
 				assert(TRIP_REF == calltrip_opr1_tref->operand[1].oprclass);
diff --git a/sr_port/expritem.c b/sr_port/expritem.c
index 1b2588e..b39c0df 100644
--- a/sr_port/expritem.c
+++ b/sr_port/expritem.c
@@ -106,6 +106,7 @@ LITDEF nametabent svn_names[] =
 	,{ 3, "ZSY*"}
 	,{ 4, "ZTCO*"}
 	,{ 4, "ZTDA*"}
+	,{ 4, "ZTDE*"}
 	,{ 3, "ZTE" }, { 4, "ZTEX*"}
 	,{ 4, "ZTLE*"}
 	,{ 4, "ZTNA*"}
@@ -125,7 +126,7 @@ LITDEF nametabent svn_names[] =
 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, 92	/* s t u v w x y z ~ */
+	22, 28, 34 ,34, 34, 34, 35, 36, 93	/* s t u v w x y z ~ */
 };
 
 /* These entries correspond to the entries in the svn_names array */
@@ -188,6 +189,7 @@ LITDEF svn_data_type svn_data[] =
 	,{ SV_ZSYSTEM, FALSE, ALL_SYS }
 	,{ SV_ZTCODE, FALSE, TRIGGER_OS }
 	,{ SV_ZTDATA, FALSE, TRIGGER_OS }
+	,{ SV_ZTDELIM, FALSE, TRIGGER_OS }
 	,{ SV_ZTEXIT, TRUE, ALL_SYS }, { SV_ZTEXIT, TRUE, ALL_SYS }
 	,{ SV_ZTLEVEL, FALSE, TRIGGER_OS}
 	,{ SV_ZTNAME, FALSE, TRIGGER_OS }
diff --git a/sr_port/f_get.c b/sr_port/f_get.c
index 8a515a5..a3cad57 100644
--- a/sr_port/f_get.c
+++ b/sr_port/f_get.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -23,7 +23,7 @@
 #include "show_source_line.h"
 
 GBLREF	boolean_t	run_time;
-GBLREF	short int	source_column;
+GBLREF	int		source_column;
 
 error_def(ERR_SIDEEFFECTEVAL);
 error_def(ERR_VAREXPECTED);
diff --git a/sr_port/f_name.c b/sr_port/f_name.c
index d5260ac..13cf1a3 100644
--- a/sr_port/f_name.c
+++ b/sr_port/f_name.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -21,7 +21,7 @@
 #include "show_source_line.h"
 
 GBLREF	boolean_t	run_time;
-GBLREF	short int	source_column;
+GBLREF	int		source_column;
 
 error_def(ERR_SIDEEFFECTEVAL);
 error_def(ERR_VAREXPECTED);
diff --git a/sr_port/f_order.c b/sr_port/f_order.c
index 18ca797..ad96e09 100644
--- a/sr_port/f_order.c
+++ b/sr_port/f_order.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -25,7 +25,7 @@
 #include "show_source_line.h"
 
 GBLREF	boolean_t	run_time;
-GBLREF	short int	source_column;
+GBLREF	int		source_column;
 
 error_def(ERR_ORDER2);
 error_def(ERR_SIDEEFFECTEVAL);
diff --git a/sr_port/find_rtn_hdr.c b/sr_port/find_rtn_hdr.c
index 62aacaa..42e9fb6 100644
--- a/sr_port/find_rtn_hdr.c
+++ b/sr_port/find_rtn_hdr.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -18,7 +18,6 @@
 #include "stack_frame.h"
 #include "compiler.h"	/* for WANT_CURRENT_RTN_MSTR macro */
 
-#define S_CUTOFF 7
 GBLREF rtn_tabent	*rtn_names, *rtn_names_end;
 GBLREF stack_frame	*frame_pointer;
 
@@ -40,7 +39,8 @@ rhdtyp	*find_rtn_hdr(mstr *name)
  * Returns FALSE otherwise.
  * In either case, also "returns" (via <res>) the rtn_tabent
  * 	corresponding to the first routine name greater than or equal to
- * 	<name>.
+ * 	<name>. This is useful for looking up trigger routines that
+ * 	include runtime disambiguators in their names.
  */
 
 boolean_t find_rtn_tabent(rtn_tabent **res, mstr *name)
@@ -49,55 +49,42 @@ boolean_t find_rtn_tabent(rtn_tabent **res, mstr *name)
 	int4		comp;
 	mident		rtn_name;
 	mident_fixed	rtn_name_buff;
+	boolean_t	ret;
+	int		len;
 
-	assert(name->len <= MAX_MIDENT_LEN);
-	rtn_name.len = name->len;
+	len = name->len;
+	rtn_name.len = MIN(MAX_MIDENT_LEN, 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 (;;)
-	{	/* See if routine exists in list via a binary search which reverts to serial
-		   search when # of items drops below the threshold S_CUTOFF.
-		*/
-		if (S_CUTOFF > (top - bot))
-		{
-			comp = -1;
-			for (mid = bot; comp < 0 && mid <= top; mid++)
-			{
-				MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
-				if (0 == comp)
-				{
-					*res = mid;
-					return TRUE;
-				} else if (0 < comp)
-					break;
-			}
+	bot = rtn_names + 1;	/* Exclude the first NULL entry */
+	top = rtn_names_end + 1;/* Include the last entry */
+	for ( ; ; )
+	{
+		if (bot == top)
 			break;
+		assert(bot < top);
+		mid = bot + (top - bot) / 2;
+		assert(mid >= bot);
+		MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
+		if (0 == comp)
+		{
+			*res = mid;
+			return TRUE;
+		} else if (0 > comp)
+		{
+			bot = mid + 1;
+			continue;
 		} else
 		{
-			mid = bot + (top - bot) / 2;
-			MIDENT_CMP(&mid->rt_name, &rtn_name, comp);
-			if (0 == comp)
-			{
-				*res = mid;
-				return TRUE;
-			}
-			else if (comp < 0)
-			{
-				bot = mid + 1;
-				continue;
-			} else
-			{
-				top = mid - 1;
-				continue;
-			}
+			assert(mid < top);
+			top = mid;
+			continue;
 		}
 	}
-	*res = mid;
+	*res = bot;
 	return FALSE;
 }
diff --git a/sr_port/flush_jmp.c b/sr_port/flush_jmp.c
index a28e3c1..335512b 100644
--- a/sr_port/flush_jmp.c
+++ b/sr_port/flush_jmp.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -49,6 +49,7 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
 	char		*top;
 	unsigned char	*msp_save;
 	int4		shift, size, mv_st_type;
+	rhdtyp		*old_rtnhdr;
 
 	unwind_nocounts();
 	/* We are going to mutate the current frame from the program it was running to the program we want it to run.
@@ -68,7 +69,12 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
 	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)));
+	old_rtnhdr = frame_pointer->rvector;
 	frame_pointer->rvector = rtn_base;
+	/* Now that fp->rvector has been overwritten to new routine, check if the older routine had a "rtn_relinked" flag set
+	 * and if so that cleanup can be performed now.
+	 */
+	USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(old_rtnhdr));	/* cleanup if needed */
 	frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base);
 	frame_pointer->vartab_len = frame_pointer->rvector->vartab_len;
 	frame_pointer->mpc = transfer_addr;
@@ -98,9 +104,9 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
 			if (msp <= stacktop)
 			{
 				msp = msp_save;
-				rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
 	   		} else
-				rts_error(VARLSTCNT(1) ERR_STACKCRIT);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT);
 	   	}
 		memset(msp, 0, size);
 		DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr"  New msp: 0x"lvaddr"\n", msp_save, msp));
@@ -155,9 +161,9 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe
    		if ((unsigned char *)mv_chain + shift <= stackwarn)
    		{
 			if ((unsigned char *)mv_chain + shift <= stacktop)
-   				rts_error(VARLSTCNT(1) ERR_STACKOFLOW);
+   				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW);
    			else
-   				rts_error(VARLSTCNT(1) ERR_STACKCRIT);
+   				rts_error_csa(CSA_ARG(NULL) 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));
diff --git a/sr_port/format2disp.c b/sr_port/format2disp.c
new file mode 100644
index 0000000..abc59c5
--- /dev/null
+++ b/sr_port/format2disp.c
@@ -0,0 +1,88 @@
+/****************************************************************
+ *								*
+ *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made available	*
+ *	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 "zshow.h"
+
+#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 displayable format. That is any nonprintable
+ * characters are replaced by a dot (.) and the rest are used as is. No double-quote
+ * additions happen like in format2zwr. Used currently by the trigger routines.
+ * This function ensures the displayed part never goes more than "displen".
+ * A "..." is inserted at the end if input string happens to be more than displen
+ * can accommodate. The truncate length is returned in "displen" in that case.
+ */
+void	format2disp(char *src, int src_len, char *dispbuff, int *displen)
+{
+	char		*c, *c_top, *nextc, *dst, *dst_top, *disptop;
+	int		chlen, dstlen, i;
+	unsigned char	ch;
+	uint4		codepoint;
+	boolean_t	isctl, isill;
+
+	dst = dispbuff;
+	dstlen = *displen;
+	if (0 > dstlen)
+		dstlen = 0;
+	disptop = dst + dstlen;
+	assert(3 < dstlen);	/* we expect caller to ensure this */
+	dstlen = (3 > dstlen)? 0 : ((dstlen < src_len) ? dstlen - 3 : dstlen); /* if neded adjust dstlen to account for ellipsis */
+	dst_top = dst + dstlen;
+	for (c = src, c_top = c + src_len; c < c_top; )
+	{
+		if (!gtm_utf8_mode)
+		{
+			ch = *c;
+			isctl = (0 != (pattern_typemask[ch] & PATM_C));
+			isill = FALSE;
+			chlen = 1;
+		}
+#		ifdef UNICODE_SUPPORTED
+		else {
+			nextc = (char *)UTF8_MBTOWC(c, c_top, codepoint);
+			isill = (WEOF == codepoint) ? (codepoint = *c, TRUE) : FALSE;
+			isctl = (!isill ? !U_ISPRINT(codepoint) : TRUE);
+			chlen = (int)(nextc - c);
+		}
+#		endif
+		if ((dst + chlen) > dst_top)
+			break;
+		if (isctl)
+		{	/* control character */
+			for (i = 0; i < chlen; i++)
+				*dst++ = '.';
+			c = c + chlen;
+		} else
+		{	/* printable character (1 byte or > 1 byte) */
+			for (i = 0; i < chlen; i++)
+				*dst++ = *c++;
+		}
+	}
+	/* Add "..." if applicable */
+	if (c < c_top)
+	{
+		if (dst < disptop)
+			*dst++ = '.';
+		if (dst < disptop)
+			*dst++ = '.';
+		if (dst < disptop)
+			*dst++ = '.';
+	}
+	*displen = dst - dispbuff;
+}
diff --git a/sr_port/gbldefs.c b/sr_port/gbldefs.c
index 76402e9..14d4e39 100644
--- a/sr_port/gbldefs.c
+++ b/sr_port/gbldefs.c
@@ -296,7 +296,8 @@ 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	short int	source_line;
+GBLDEF	int		source_column;
 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
@@ -405,8 +406,6 @@ GBLDEF	int			gtmrecv_srv_count;
 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;
@@ -717,7 +716,6 @@ GBLDEF	boolean_t	gvdupsetnoop = TRUE;	/* if TRUE, duplicate SETs do not change G
 						 * 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 */
@@ -973,6 +971,7 @@ GBLDEF	boolean_t 	*ztvalue_changed_ptr;		/* -> boolean in current gtm_trigger_pa
 GBLDEF	boolean_t	ztwormhole_used;		/* TRUE if $ztwormhole was used by trigger code */
 GBLDEF	mstr		*dollar_ztname;
 GBLDEF	mval		*dollar_ztdata,
+			*dollar_ztdelim,
 			*dollar_ztoldval,
 			*dollar_ztriggerop,
 			*dollar_ztupdate,
@@ -1113,5 +1112,4 @@ GBLDEF	gtm_tls_ctx_t	*tls_ctx;			/* Process private pointer to SSL/TLS context.
 							 * Socket devices.
 							 */
 #endif
-
 GBLDEF lv_val		*active_lv;
diff --git a/sr_port/gde.hlp b/sr_port/gde.hlp
index a9a7eb5..46847df 100644
--- a/sr_port/gde.hlp
+++ b/sr_port/gde.hlp
@@ -141,7 +141,6 @@
                      Jnl File (def ext: .mjl)  Before  Buff      Alloc      Exten   AutoSwitch
     ------------------------------------------------------------------------------------------
     <default>        <based on DB file-spec>   Y       2308       2048       2048      8386560
-
     Segment          Active              Acc Typ Block      Alloc Exten Options
     ------------------------------------------------------------------------------
     <default>          *                 BG  DYN  4096       5000 10000 GLOB =1000
@@ -152,25 +151,21 @@
     <default>                            MM  DYN  4096       5000 10000 DEFER
                                                                         LOCK = 40
                                                                         MSLT =1024
-
             *** 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
     -------------------------------------------------------------------------------------------
@@ -180,7 +175,6 @@
                                                                                        RES =   0
                                                                                        ENCR=OFF
                                                                                        MSLT=1024
-
                                      *** MAP ***
       -  -  -  -  -  -  -  -  -  - Names -  -  - -  -  -  -  -  -  -
     From                            Up to                            Region / Segment / File(def ext: .dat)
@@ -721,7 +715,6 @@
 
    GDE> add    -gblname EURCentral -collation=1
    GDE> show   -gblname
-
             *** GBLNAMES ***
     Global                             Coll  Ver
     ------------------------------------------------------------------------------
@@ -1063,7 +1056,6 @@
    Example:
 
    GDE>show -template
-
                                   *** TEMPLATES ***
                                                                              Std      Inst
                                                 Def     Rec   Key Null       Null     Freeze   Qdb
@@ -1073,7 +1065,6 @@
                      Jnl File (def ext: .mjl)  Before  Buff      Alloc      Exten   AutoSwitch
     ------------------------------------------------------------------------------------------
     <default>        <based on DB file-spec>   Y       2308       2048       2048      8386560
-
     Segment          Active              Acc Typ Block      Alloc Exten Options
     ------------------------------------------------------------------------------
     <default>          *                 BG  DYN  4096       5000 10000 GLOB =1000
@@ -2048,15 +2039,16 @@
 
    Copyright 2014
 
-   Fidelity Information Services, Inc. All rights reserved.
+   Fidelity National Information Services, Inc. and/or its subsidiaries. All
+   rights reserved.
 
    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or any
    later version published by the Free Software Foundation; with no Invariant
    Sections, no Front-Cover Texts and no Back-Cover Texts.
 
-   GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
-   trademarks are the property of their respective owners.
+   GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+   Other trademarks are the property of their respective owners.
 
    This document contains a description of GT.M and the operating
    instructions pertaining to the various functions that comprise the system.
@@ -2067,7 +2059,7 @@
 
    **Note**
 
-   This help file is a concise representation of revision V6.2-000 of the
+   This help file is a concise representation of revision V6.2-001 of the
    UNIX Administration and Operations Guide. To obtain a copy of the current
    revision, go to www.fis-gtm.com and then click on the User Documentation
    tab.
diff --git a/sr_port/gdsbt.h b/sr_port/gdsbt.h
index 64f9115..7d22808 100644
--- a/sr_port/gdsbt.h
+++ b/sr_port/gdsbt.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -391,7 +391,7 @@ typedef struct node_local_struct
 	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 */
+	NON_GTM64_ONLY(int4 filler_8byte_align;) /* To align the following member at an 8-byte boundary 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	*/
@@ -425,6 +425,8 @@ typedef struct node_local_struct
 	 */
 	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 */
+	boolean_t	doing_epoch;		/* set when performing an epoch */
+	NON_GTM64_ONLY(int4 filler_8byte_align1;) /* 8-byte align the stucture on 32-bit platforms; 64s do it implicitly */
 #	endif
 } node_local;
 
diff --git a/sr_port/gdsdbver.h b/sr_port/gdsdbver.h
index fbaa364..beb0301 100644
--- a/sr_port/gdsdbver.h
+++ b/sr_port/gdsdbver.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -69,6 +69,7 @@ enum mdb_ver
 	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 */
+	GDSMV62001,	/* New field hasht_upgrade_needed for ^#t upgrade */
 	GDSMVLAST
 };
 #define GDSMVCURR ((enum mdb_ver)(GDSMVLAST - 1))
diff --git a/sr_port/gdsfhead.h b/sr_port/gdsfhead.h
index e6cbcbf..99fe5fa 100644
--- a/sr_port/gdsfhead.h
+++ b/sr_port/gdsfhead.h
@@ -221,8 +221,8 @@ 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);
+gtm_uint64_t verify_queue_lock(que_head_ptr_t qhdr);
+gtm_uint64_t verify_queue(que_head_ptr_t qhdr);
 
 #ifdef DB64
 # ifdef __osf__
@@ -231,8 +231,8 @@ void verify_queue(que_head_ptr_t qhdr);
 #endif
 
 #ifdef DEBUG_QUEUE
-#define VERIFY_QUEUE(base)      	verify_queue(base)
-#define VERIFY_QUEUE_LOCK(base,latch)	verify_queue_lock(base,latch)
+#define VERIFY_QUEUE(base)		(void)verify_queue(base)
+#define VERIFY_QUEUE_LOCK(base,latch)	(void)verify_queue_lock(base,latch)
 #else
 #define VERIFY_QUEUE(base)
 #define VERIFY_QUEUE_LOCK(base,latch)
@@ -834,6 +834,8 @@ void verify_queue(que_head_ptr_t qhdr);
 				assert(reg->open);						\
 				cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs;			\
 				cs_data = cs_addrs->hdr;					\
+				assert((&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs)		\
+					&& cs_addrs->hdr == cs_data);				\
 				break;								\
 			case dba_usr:								\
 			case dba_cm:								\
@@ -845,7 +847,6 @@ void verify_queue(que_head_ptr_t qhdr);
 				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)				\
@@ -1499,18 +1500,42 @@ n_db_csh_acct_rec_types
 #undef TAB_DB_CSH_ACCT_REC
 
 #include "gvstats_rec.h"
+#ifdef UNIX
+#include "probecrit_rec.h"
+#endif
 
 #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;			\
+#define	INCR_GVSTATS_COUNTER(csa, cnl, counter, increment)			\
+{										\
+	csa->gvstats_rec.counter += increment;	/* process private stats */	\
+	cnl->gvstats_rec.counter += increment;	/* database stats */		\
+}
+
+/* clear everything from the end of the encryption_hash up to the ntrpt_recov_resync_strm_seqno array, which includes:
+ * all bg_trc_rec_tn, all bg_trc_rec_cntr, all db_csh_acct_rec, all gvstats as well as any intervening filler;
+ * also clear tp_cdb_sc_blkmod
+ * This means we MUST NOT insert anything in the file header between the encryption_hash and intrpt_recov_resync_strm_seqno
+ * nor move either of those end points without appropriately adjusting this macro
+ */
+#define	CLRGVSTATS(CSA)									\
+{											\
+	char			*CHPTR;							\
+	int			CLRLEN;							\
+	sgmnt_data_ptr_t	CSD;							\
+											\
+	CSD = CSA->hdr;									\
+	CHPTR = (char *)&CSD->encryption_hash + GTMCRYPT_RESERVED_HASH_LEN;		\
+	CLRLEN = (char *)&CSD->intrpt_recov_resync_strm_seqno - CHPTR;			\
+	memset(CHPTR, 0, CLRLEN);							\
+	gvstats_rec_csd2cnl(CSA);	/* we update gvstats in cnl */			\
+	memset((char *)&CSD->tp_cdb_sc_blkmod, 0, SIZEOF(CSD->tp_cdb_sc_blkmod));	\
 }
 
+
 #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)		\
@@ -1547,6 +1572,7 @@ enum tp_blkmod_type		/* used for accounting in cs_data->tp_cdb_sc_blkmod[] */
 #define DONOTCOMMIT_REALLOCATE_BITMAP_BMLMOD		(1 << 8) /* Restartable situation encountered in reallocate_bitmap */
 #define DONOTCOMMIT_T_WRITE_CSE_DONE			(1 << 9) /* Restartable situation encountered in t_write */
 #define DONOTCOMMIT_T_WRITE_CSE_MODE			(1 << 10) /* Restartable situation encountered in t_write */
+#define DONOTCOMMIT_TRIGGER_SELECT_XECUTE		(1 << 11) /* Restartable situation encountered in trigger_select */
 
 #define TAB_BG_TRC_REC(A,B)	B,
 enum bg_trc_rec_type
@@ -1818,7 +1844,12 @@ typedef struct sgmnt_data_struct
 	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. */
+	 * consumes 256 bytes, filler_2k has been removed.
+	 */
+	/* The CLRGVSTATS macro wipes out everything from here through the GVSTATS fields up to intrpt_recov_resync_strm_seqno
+	 * starting from the end of the space reserved for the encryption_hash above - DO NOT insert anthing in this range or move
+	 * those two end points without appropriately adjusting that macro
+	 */
 	/************* BG_TRC_REC RELATED FIELDS ***********/
 #	define TAB_BG_TRC_REC(A,B)	bg_trc_rec_tn	B##_tn;
 #	include "tab_bg_trc_rec.h"
@@ -1867,10 +1898,12 @@ typedef struct sgmnt_data_struct
 								 * See comment in "mur_get_max_strm_reg_seqno" function for
 								 * purpose of this field. Must also be 8-byte aligned.
 								 */
+	/************* MISCELLANEOUS FIELDS ****************/
 	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];
+	boolean_t	hasht_upgrade_needed;	/* ^#t global needs to be upgraded from V62000 to post-V62000 format */
+	char		filler_7k[720];
 	char		filler_8k[1024];
 	/********************************************************/
 	/* Master bitmap immediately follows. Tells whether the local bitmaps have any free blocks or not. */
@@ -1923,6 +1956,8 @@ typedef struct
 #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 */
+#define MIN_GBUFF_LIMIT	32	/* minimum gbuff limit */
+#define REORG_GBUFF_LIMIT "64"	/* default gbuff_limit for REORG */
 
 /* definition for NULL_SUBSCRIPTS */
 #define NEVER		0
@@ -2237,12 +2272,16 @@ typedef struct	sgmnt_addrs_struct
 						 * should know to release crit even if hold_onto_crit is set to TRUE and so will
 						 * rely on this variable
 						 */
+	int4		gbuff_limit;		/* desired limit on global buffers; see db_csh_getn, op_view and op_fnview */
+	cache_rec_ptr_t	our_midnite;		/* anchor if we are using a gbuff_limit */
 #	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 */
 	boolean_t	read_only_fs;		/* TRUE if the region is read_only and the header was not updated due to EROFS */
+	boolean_t	crit_probe;		/* flag for indicating the process is doing a crit probe on this region */
+	probecrit_rec_t	probecrit_rec;		/* fields defined in tab_probecrit_rec.h and initialized in probecrit_rec.h */
 #	endif
 } sgmnt_addrs;
 
@@ -2668,6 +2707,10 @@ typedef struct	gvnh_reg_struct
 	assert(added);												\
 }
 
+/* Below macro is used whenever we need to print region of interest in case of a global that spans multiple regions */
+#define	SPANREG_REGION_LIT	" (region "
+#define	SPANREG_REGION_LITLEN	STR_LIT_LEN(SPANREG_REGION_LIT)
+
 #define INVALID_GV_TARGET (gv_namehead *)-1L
 /* Below macro is used to get the "gvnh_reg->gvspan->gvt_array[]" contents taking into account some
  * might be set to INVALID_GV_TARGET (done only in DEBUG mode). In that case, we actually want to return NULL
@@ -2843,6 +2886,10 @@ GBLREF	gv_namehead	*gvt_tp_list;
  * 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.
+ *
+ * Update: The above comment is no longer true. As part of GTM-2168, the fast path in op_gvname was removed but we have not
+ * removed code that does the below macro invocation since this is dbg-only and is anyways otherwise true. If it is a hassle
+ * ensuring the below anywhere, it should be okay to remove it then.
  */
 #define	DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS)									\
 {																\
@@ -3570,8 +3617,6 @@ typedef replpool_identifier 	*replpool_id_ptr_t;
 	}										\
 }
 
-#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 */
diff --git a/sr_port/gtm_env_init.c b/sr_port/gtm_env_init.c
index acde640..931e706 100644
--- a/sr_port/gtm_env_init.c
+++ b/sr_port/gtm_env_init.c
@@ -167,6 +167,24 @@ void	gtm_env_init(void)
 			}
 		} else
 			(TREF(mprof_env_gbl_name)).str.addr = NULL;
+		val.addr = GTM_POOLLIMIT;
+		val.len = SIZEOF(GTM_POOLLIMIT) - 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(gbuff_limit)).str.len = 0;
+				else
+				{
+					(TREF(gbuff_limit)).str.len = trans.len;
+					(TREF(gbuff_limit)).str.addr = malloc(trans.len);
+					memcpy((TREF(gbuff_limit)).str.addr, trans.addr, trans.len);
+				}
+			}
+		} else
+			(TREF(gbuff_limit)).str.len = 0;
+		(TREF(gbuff_limit)).mvtype = MV_STR;
 #		ifdef DEBUG
 		/* GTM_GVUNDEF_FATAL environment/logical */
 		val.addr = GTM_GVUNDEF_FATAL;
diff --git a/sr_port/gtm_stdlib.h b/sr_port/gtm_stdlib.h
index 225827a..29c8748 100644
--- a/sr_port/gtm_stdlib.h
+++ b/sr_port/gtm_stdlib.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -16,34 +16,50 @@
 #include <stdlib.h>
 
 #ifndef __CYGWIN__
-#define GETENV	getenv
+#  define GETENV	getenv
 #else
 char *gtm_getenv(char *varname);
-#define GETENV gtm_getenv
+#  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
+#define ATOI		atoi
+#define ATOL		atol
+#define ATOF		atof
+#ifdef UNIX
+/* If interrupted, this function has previously caused hangs to do a subsequent syslog() invocation from generic_signal_handler(),
+ * so just defer interrupts to be safe. UNIX is a GT.M-specific compiler switch, which we expect to be undefined for any non-GT.M
+ * compilation that might include this file.
+ */
+#  define PUTENV(VAR, ARG)				\
+{							\
+	DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC);	\
+	VAR = putenv(ARG);				\
+	ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC);	\
+}
+#else
+#  define PUTENV(VAR, ARG)				\
+{							\
+	VAR = putenv(ARG);				\
+}
+#endif
+#define STRTOL		strtol
+#define STRTOLL		strtoll
+#define STRTOUL		strtoul
 #if INT_MAX < LONG_MAX	/* like Tru64 */
-#define STRTO64L	strtol
-#define STRTOU64L	strtoul
+#  define STRTO64L	strtol
+#  define STRTOU64L	strtoul
 #elif defined(__hpux)
-#include <inttypes.h>
-#define STRTO64L	strtoimax
-#define STRTOU64L	strtoumax
+#  include <inttypes.h>
+#  define STRTO64L	strtoimax
+#  define STRTOU64L	strtoumax
 #else
-#define STRTO64L	strtoll
-#define STRTOU64L	strtoull
+#  define STRTO64L	strtoll
+#  define STRTOU64L	strtoull
 #endif
 #define MKSTEMP(template,mkstemp_res)	(mkstemp_res = mkstemp(template))
-#ifdef VMS
-#define SYSTEM system
+#if defined(VMS) || defined(STATIC_ANALYSIS)
+#  define SYSTEM	system
 #else
-#define SYSTEM	gtm_system
+#  define SYSTEM	gtm_system
 int gtm_system(const char *cmdline);
 #endif
 
diff --git a/sr_port/gtm_threadgbl.h b/sr_port/gtm_threadgbl.h
index f87ab53..6e6ebe8 100644
--- a/sr_port/gtm_threadgbl.h
+++ b/sr_port/gtm_threadgbl.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -35,6 +35,8 @@
  * 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.
+ * TLEN			    - Used to obtain length of total element for both one and two dimension arrays. Not
+ *			      defined for non-arrays.
  * 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.
@@ -82,6 +84,9 @@
 /* For address of item use TADR(name) macro */
 #define TADR(name) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name))
 
+/* For character length of character arrays (for arrays only) */
+#define TLEN(name) (ggl_##name)
+
 /* For access to single dimension array (vector), use TAREF1 macro */
 #define TAREF1(name, indx1) (TADR(name))[indx1]
 
diff --git a/sr_port/gtm_threadgbl_defs.h b/sr_port/gtm_threadgbl_defs.h
index 4bb2098..231e386 100644
--- a/sr_port/gtm_threadgbl_defs.h
+++ b/sr_port/gtm_threadgbl_defs.h
@@ -50,13 +50,20 @@ 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(defined_symbols,			struct sym_table *)		/* Anchor for symbol chain */
 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(last_source_column,		int)				/* parser tracker */
+THREADGBLDEF(max_advancewindow_line,		int4)				/* the maximum source line length */
+THREADGBLDEF(linkage_first,			struct linkage_entry *)		/* Start of linkage (extern) list this routine */
+THREADGBLDEF(linkage_last,			struct linkage_entry *)		/* Last added entry */
+#ifdef USHBIN_SUPPORTED
+THREADGBLDEF(objhash_state,			hash128_state_t)		/* Seed value - progressive hash of object file */
+#endif
 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(routine_source_offset,		uint4)				/* offset of M source within literal text pool */
@@ -80,6 +87,7 @@ THREADGBLDEF(dbinit_max_hrtbt_delta,		uint4)				/* max heartbeats before we bail
 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(gbuff_limit,			mval)				/* holds a GTM_POOLLIMIT value for REORG or DBG */
 THREADGBLDEF(gd_targ_tn,			trans_num)			/* number that is incremented for every gvcst_spr*
 										 * action. helps easily determine whether a region
 										 * has already been seen in this gvcst_spr* action.
@@ -191,6 +199,8 @@ THREADGBLDEF(replgbl,				replgbl_t)			/* set of global variables needed by the s
 										 * server */
 THREADGBLDEF(tqread_nowait,			boolean_t)			/* avoid sleeping in t_qread if TRUE */
 /* Miscellaneous */
+THREADGBLDEF(arlink_enabled,			boolean_t)			/* TRUE if any zroutines segment is autorelink
+										 * enabled. */
 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 */
@@ -260,9 +270,13 @@ THREADGBLDEF(mprof_reclaim_cnt,			int)				/* Amount of mem to reclaim after unw_
 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 USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 THREADGBLDEF(open_relinkctl_list,		open_relinkctl_sgm *)		/* Anchor for open relinkctl list; similar to
 										 * open_shlib_root */
+THREADGBLDEF(relinkctl_shm_min_index,		int)				/* Minimum size of rtnobj shared memory segment
+										 * is 2**relinkctl_shm_min_index
+										 */
+THREADGBLDEF(gtm_autorelink_keeprtn,		boolean_t)			/* do not let go of objects in rtnobj shm */
 #endif
 #ifdef UNIX
 THREADGBLDEF(open_shlib_root,			open_shlib *)			/* Anchor for open shared library list */
@@ -277,9 +291,6 @@ THREADGBLDEF(pipefifo_interrupt,		int)				/* count of number of times a pipe or
 										 * interrupted */
 #endif
 THREADGBLDEF(prof_fp,				mprof_stack_frame *)		/* Stack frame that mprof currently operates on */
-#ifdef USHBIN_SUPPORTED
-THREADGBLDEF(recent_zhist,			zro_hist *)			/* Saved history from last zro_search */
-#endif
 THREADGBLDEF(relink_allowed,			int)				/* Non-zero if recursive relink permitted */
 THREADGBLDEF(set_zroutines_cycle,		uint4)				/* Informs us if we changed $ZROUTINES between
 										 * linking a routine and invoking it
@@ -329,6 +340,7 @@ THREADGBLAR1DEF(tp_restart_failhist_arry,	char,	FAIL_HIST_ARRAY_SIZE)	/* tp_rest
 THREADGBLDEF(user_id,				uint4)				/* USERID number */
 #endif
 THREADGBLAR1DEF(window_string,			char,	SIZEOF(mident_fixed))	/* Buffer for window_ident */
+THREADGBLAR1DEF(tmp_object_file_name,		char,	GTM_PATH_MAX)		/* Hold temporary object name across routines */
 
 /* Utility I/O */
 THREADGBLDEF(last_va_list_ptr,			va_list)			/* Last variable-length argument list used for util
@@ -347,6 +359,9 @@ THREADGBLDEF(extcall_package_root,		struct extcall_package_list *)	/* External c
 #ifdef UNIX
 THREADGBLDEF(gtmci_nested_level,		unsigned int)			/* Current nested depth of callin environments */
 THREADGBLDEF(temp_fgncal_stack,			unsigned char *)		/* Override for fgncal_stack when non-NULL */
+THREADGBLDEF(midchild_send_locals,		boolean_t)			/* The middle child will send the locals to the
+										 * grandchild using ojmidchild_send_var() if TRUE.
+										 */
 #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
@@ -391,6 +406,7 @@ THREADGBLDEF(no_spangbls,			boolean_t)	/* This process does not need to worry ab
 								 * irrespective of whether the global spans regions or not.
 								 */
 THREADGBLDEF(max_fid_index,			int)		/* maximum value of csa->fid_index across all open csa's */
+THREADGBLDEF(is_mu_rndwn_rlnkctl,		int)		/* this process is MUPIP RUNDOWN -RELINKCTL */
 #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.
@@ -407,6 +423,13 @@ THREADGBLDEF(op_fntext_tlevel,			uint4)				/* Non-zero implies $TEXT argument is
 										 * the time of the call to "get_src_line" in
 										 * op_fntext.c. Later used by fntext_ch.c.
 										 */
+THREADGBLDEF(in_op_fntext,			boolean_t)			/* Denote the trigger was processed in $Text() */
+THREADGBLDEF(ztrigbuff,				char *)				/* Buffer to hold $ztrigger/mupip-trigger output
+										 * until TCOMMIT.
+										 */
+THREADGBLDEF(ztrigbuffAllocLen,			int)				/* Length of allocated ztrigbuff buffer */
+THREADGBLDEF(ztrigbuffLen,			int)				/* Length of used ztrigbuff buffer */
+THREADGBLDEF(ztrig_use_io_curr_device,		boolean_t)	/* Use current IO device instead of stderr/util_out_print */
 #endif
 
 /* Debug values */
@@ -435,4 +458,14 @@ THREADGBLDEF(activelv_dbg_array,		activelv_dbg_t *)	/* pointer to array holding
 									 * ACTIVELV_DBG_ARRAY_SIZE_DEF most recent
 									 * invocations of SET_ACTIVE_LV */
 THREADGBLDEF(cli_get_str_max_len,		uint4)
-#endif
+# ifdef GTM_TRIGGER
+THREADGBLDEF(gtmio_skip_tlevel_assert,		boolean_t)	/* Allow for "util_out_print_gtmio" calls without TP
+								 * if this variable is TRUE.
+								 */
+THREADGBLDEF(in_trigger_upgrade,		boolean_t)	/* caller is MUPIP TRIGGER -UPGRADE */
+#endif	/* #ifdef GTM_TRIGGER */
+THREADGBLDEF(gtm_test_autorelink_always,	boolean_t)	/*  DEBUG-only option to enable/disable autorelink always */
+THREADGBLDEF(fork_without_child_wait,		boolean_t)	/*  we did a FORK but did not wait for child to detach from
+								 *  inherited shm so shm_nattch could be higher than we expect.
+								 */
+#endif	/* #ifdef DEBUG */
diff --git a/sr_port/gtm_threadgbl_deftypes.c b/sr_port/gtm_threadgbl_deftypes.c
index 1791cd3..61aa998 100644
--- a/sr_port/gtm_threadgbl_deftypes.c
+++ b/sr_port/gtm_threadgbl_deftypes.c
@@ -23,7 +23,7 @@
 #include <signal.h>
 #include <sys/time.h>
 #ifdef UNIX
-# include <sys/un.h>
+# include "gtm_un.h"
 #endif
 #ifdef VMS
 # include <descrip.h>		/* Required for gtmsource.h */
@@ -142,9 +142,8 @@
 # include "gtm_trigger.h"
 #endif
 
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 # include "relinkctl.h"
-# include "zhist.h"
 #endif
 
 /* This module's purpose is to generate gtm_threadgbl_deftypes.h for a given platform. This header file
diff --git a/sr_port/gtm_threadgbl_init.c b/sr_port/gtm_threadgbl_init.c
index 5b4486c..b41d38a 100644
--- a/sr_port/gtm_threadgbl_init.c
+++ b/sr_port/gtm_threadgbl_init.c
@@ -29,12 +29,10 @@
 #include "gtm_socket.h"
 #include "gtm_unistd.h"
 #include "gtm_limits.h"
+#include "gtm_un.h"
 
 #include <signal.h>
 #include <sys/time.h>
-#ifdef UNIX
-# include <sys/un.h>
-#endif
 #ifdef VMS
 # include <descrip.h>		/* Required for gtmsource.h */
 # include <ssdef.h>
@@ -152,9 +150,8 @@
 # include "gtm_trigger.h"
 #endif
 
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 # include "relinkctl.h"
-# include "zhist.h"
 #endif
 
 #include "gtm_threadgbl_init.h"
@@ -228,4 +225,6 @@ void gtm_threadgbl_init(void)
 	(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. */
+	TREF(util_outptr) = TREF(util_outbuff_ptr);
+	TREF(max_advancewindow_line) = MAX_SRCLINE;
 }
diff --git a/sr_port/gtmrecv_helpers_init.c b/sr_port/gtmrecv_helpers_init.c
index fd194cf..d3097e7 100644
--- a/sr_port/gtmrecv_helpers_init.c
+++ b/sr_port/gtmrecv_helpers_init.c
@@ -44,8 +44,10 @@
 #include "memcoherency.h"
 #include "getjobnum.h"
 #include "gtmimagename.h"
+#include "wbox_test_init.h"
 
-#define UPDHELPER_CMD_MAXLEN		1024
+
+#define UPDHELPER_CMD_MAXLEN		GTM_PATH_MAX
 #define UPDHELPER_CMD			"%s/mupip"
 #define UPDHELPER_CMD_FILE		"mupip"
 #define UPDHELPER_CMD_ARG1		"replicate"
@@ -68,6 +70,7 @@ error_def(ERR_GTMDISTUNVERIF);
 error_def(ERR_LOGTOOLONG);
 error_def(ERR_RECVPOOLSETUP);
 error_def(ERR_TEXT);
+error_def(ERR_HLPPROC);
 
 static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
 {
@@ -93,13 +96,27 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
 	if (!gtm_dist_ok_to_use)
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMDISTUNVERIF, 4, STRLEN(gtm_dist), gtm_dist,
 				gtmImageNames[image_type].imageNameLen, gtmImageNames[image_type].imageName);
+	if (WBTEST_ENABLED(WBTEST_MAXGTMDIST_HELPER_PROCESS))
+	{
+		memset(gtm_dist, 'a', GTM_PATH_MAX-2);
+		gtm_dist[GTM_PATH_MAX-1] = '\0';
+	}
+	helper_cmd_len = SNPRINTF(helper_cmd, UPDHELPER_CMD_MAXLEN, UPDHELPER_CMD, gtm_dist);
+	if ((-1 == helper_cmd_len) || (UPDHELPER_CMD_MAXLEN <= helper_cmd_len))
+	{
+		helper->helper_shutdown = save_shutdown;
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_HLPPROC, 0, ERR_TEXT, 2,
+			   LEN_AND_LIT("Could not find path of Helper Process. Check value of $gtm_dist"));
+		repl_errno = EREPL_UPDSTART_BADPATH;
+		return UPDPROC_START_ERR ;
+	}
 	FORK(helper_pid);
 	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);
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_HLPPROC, 0, ERR_TEXT, 2,
+				LEN_AND_LIT("Could not fork Helper process"), save_errno);
 		repl_errno = EREPL_UPDSTART_FORK;
 		return UPDPROC_START_ERR;
 	}
@@ -107,24 +124,17 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
 	{	/* helper */
 		getjobnum();
 		helper->helper_pid_prev = process_id; /* identify owner of slot */
-		helper_cmd_len = SNPRINTF(helper_cmd, UPDHELPER_CMD_MAXLEN, UPDHELPER_CMD, gtm_dist);
-		if(-1 == helper_cmd_len)
-		{
-			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"));
-			repl_errno = EREPL_UPDSTART_BADPATH;
-			return UPDPROC_START_ERR;
-		}
+		if (WBTEST_ENABLED(WBTEST_BADEXEC_HELPER_PROCESS))
+			STRCPY(helper_cmd, "ersatz");
 		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,
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_HLPPROC, 0, ERR_TEXT, 2,
 				   LEN_AND_LIT("Could not exec Helper Process"), save_errno);
 			repl_errno = EREPL_UPDSTART_EXEC;
-			return UPDPROC_START_ERR;
+			_exit(UPDPROC_START_ERR);
 		}
 	}
 #elif defined(VMS)
diff --git a/sr_port/gtmrecv_upd_proc_init.c b/sr_port/gtmrecv_upd_proc_init.c
index 0d84541..df50d66 100644
--- a/sr_port/gtmrecv_upd_proc_init.c
+++ b/sr_port/gtmrecv_upd_proc_init.c
@@ -45,8 +45,9 @@
 #include "repl_log.h"
 #include "eintr_wrappers.h"
 #include "gtmimagename.h"
+#include "wbox_test_init.h"
 
-#define UPDPROC_CMD_MAXLEN	1024
+#define UPDPROC_CMD_MAXLEN	GTM_PATH_MAX
 #define UPDPROC_CMD		"%s/mupip"
 #define UPDPROC_CMD_FILE	"mupip"
 #define UPDPROC_CMD_ARG1	"replicate"
@@ -68,6 +69,7 @@ error_def(ERR_LOGTOOLONG);
 error_def(ERR_RECVPOOLSETUP);
 error_def(ERR_REPLINFO);
 error_def(ERR_TEXT);
+error_def(ERR_UPDPROC);
 
 int gtmrecv_upd_proc_init(boolean_t fresh_start)
 {
@@ -101,7 +103,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
 		return(UPDPROC_EXISTS);
 	} else if (upd_status == SRV_ALIVE)
 	{
-		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
 			   RTS_ERROR_LITERAL("Update process already exists. Please kill it before a fresh start"));
 		return(UPDPROC_EXISTS);
 	}
@@ -113,11 +115,24 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
 	if (!gtm_dist_ok_to_use)
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMDISTUNVERIF, 4, STRLEN(gtm_dist), gtm_dist,
 				gtmImageNames[image_type].imageNameLen, gtmImageNames[image_type].imageName);
+	if (WBTEST_ENABLED(WBTEST_MAXGTMDIST_UPDATE_PROCESS))
+	{
+		memset(gtm_dist, 'a', GTM_PATH_MAX-2);
+		gtm_dist[GTM_PATH_MAX-1] = '\0';
+	}
+	upd_proc_cmd_len = SNPRINTF(upd_proc_cmd, UPDPROC_CMD_MAXLEN, UPDPROC_CMD, gtm_dist);
+	if ((-1 == upd_proc_cmd_len) || (UPDPROC_CMD_MAXLEN <= upd_proc_cmd_len))
+	{
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
+			   RTS_ERROR_LITERAL("Could not find path of Update Process. Check value of $gtm_dist"));
+		repl_errno = EREPL_UPDSTART_BADPATH;
+		return(UPDPROC_START_ERR);
+	}
 	FORK(upd_pid);
 	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,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_UPDPROC, 0, ERR_TEXT, 2,
 			   RTS_ERROR_LITERAL("Could not fork update process"), errno);
 		repl_errno = EREPL_UPDSTART_FORK;
 		return(UPDPROC_START_ERR);
@@ -125,20 +140,14 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
 	if (0 == upd_pid)
 	{
 		/* Update Process */
-		upd_proc_cmd_len = SNPRINTF(upd_proc_cmd, UPDPROC_CMD_MAXLEN, UPDPROC_CMD, gtm_dist);
-		if (-1 == upd_proc_cmd_len)
-		{
-			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"));
-			repl_errno = EREPL_UPDSTART_BADPATH;
-			return(UPDPROC_START_ERR);
-		}
+		if (WBTEST_ENABLED(WBTEST_BADEXEC_UPDATE_PROCESS))
+		                STRCPY(upd_proc_cmd, "ersatz");
 		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,
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_UPDPROC, 0, ERR_TEXT, 2,
 				   RTS_ERROR_LITERAL("Could not exec Update Process"), errno);
 			repl_errno = EREPL_UPDSTART_EXEC;
-			return(UPDPROC_START_ERR);
+			_exit(UPDPROC_START_ERR);
 		}
 	}
 #elif defined(VMS)
@@ -190,12 +199,12 @@ int gtmrecv_start_updonly(void)
 
 	if ((upd_status = is_updproc_alive()) == SRV_ALIVE)
 	{
-		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 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,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
 			   RTS_ERROR_LITERAL("Error in starting up update process"));
 		return(UPDPROC_START_ERR);
 	}
@@ -220,15 +229,15 @@ int gtmrecv_start_updonly(void)
 #endif
 	if (start_status == UPDPROC_START)
 	{
-		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 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,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 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,
+		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDPROC, 0, ERR_TEXT, 2,
 			   RTS_ERROR_LITERAL("Update Process exists already. New process not started"));
 	}
 	return(UPDPROC_START_ERR);
diff --git a/sr_port/gv_select.c b/sr_port/gv_select.c
index eaa6cdf..9630afc 100644
--- a/sr_port/gv_select.c
+++ b/sr_port/gv_select.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -46,6 +46,15 @@
 #include "gvnh_spanreg.h"
 #include "change_reg.h"
 
+#ifdef EXTRACT_HASHT_GLOBAL
+# include "gv_trigger_common.h"	/* for IS_GVKEY_HASHT_GBLNAME and HASHT_GBL_CHAR1 macros */
+# ifdef GTM_TRIGGER
+#  include "gv_trigger.h"
+#  include "targ_alloc.h"
+#  include "gvcst_protos.h"	/* for gvcst_root_search prototype used in GVTR_SWITCH_REG_AND_HASHT_BIND_NAME macro */
+# endif
+#endif
+
 #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);
@@ -89,6 +98,11 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
 #	else
 	hash_table_int4		ext_hash;
 #	endif
+#	ifdef EXTRACT_HASHT_GLOBAL
+	gvnh_reg_t		*hashgbl_gvnh_reg = NULL;
+	gd_region		*r_top;
+	sgmnt_addrs		*csa;
+#	endif
 
 	memset(gmap, 0, SIZEOF(gmap));
 	gmap_size = SIZEOF(gmap) / SIZEOF(gmap[0]);
@@ -231,6 +245,39 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
 			 */
 			if (MAX_MIDENT_LEN < curr_gbl_name.str.len)
 				curr_gbl_name.str.len = MAX_MIDENT_LEN;
+#			if defined(GTM_TRIGGER) && defined(EXTRACT_HASHT_GLOBAL)
+			if (HASHT_GBL_CHAR1 == curr_gbl_name.str.addr[0])
+			{	/* Global names starting with "#" e.g. ^#t. Consider these as spanning across
+				 * all regions of the gbldir for the purposes of the caller (MUPIP EXTRACT
+				 * or MUPIP REORG or MUPIP SIZE).
+				 */
+				if (NULL == hashgbl_gvnh_reg)
+				{
+					hashgbl_gvnh_reg = (gvnh_reg_t *)malloc(SIZEOF(gvnh_reg_t));
+					/* initialize gvnh_reg fields to NULL specifically gvnh_reg->gvspan
+					 * as this is used by the caller of gv_select.
+					 */
+					memset(hashgbl_gvnh_reg, 0, SIZEOF(gvnh_reg_t));
+				}
+				/* At this time, only ^#t is supported. In the future ^#k or some such globals
+				 * might be supported for other purposes. The following code needs to change if/when
+				 * that happens.
+				 */
+				assert(IS_GVKEY_HASHT_GBLNAME(curr_gbl_name.str.len, curr_gbl_name.str.addr));
+				if (!gd_header)
+					gvinit();
+				for (reg = gd_header->regions, r_top = reg + gd_header->n_regions; reg < r_top; reg++)
+				{
+					GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+					csa = cs_addrs;
+					if (NULL == csa)	/* not BG or MM access method */
+						continue;
+					gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key,
+									reg_max_blk, restrict_reg, hashgbl_gvnh_reg, &gl_tail);
+				}
+				break;
+			}
+#			endif
 			COMPUTE_HASH_MSTR(curr_gbl_name.str, hash_code);
 			op_gvname_fast(VARLSTCNT(2) hash_code, &curr_gbl_name);
 			assert((dba_bg == REG_ACC_METH(gv_cur_region)) || (dba_mm == REG_ACC_METH(gv_cur_region)));
@@ -246,8 +293,9 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
 				gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key, reg_max_blk,
 										restrict_reg, gvnh_reg, &gl_tail);
 			else
-			{	/* If global spans multiple regions, make sure gv_targets corresponding to ALL spanned regions
-				 * are allocated and gv_target->root is also initialized accordingly for all the spanned regions.
+			{	/* If global spans multiple regions, make sure gv_targets corresponding to ALL
+				 * spanned regions are allocated and gv_target->root is also initialized
+				 * accordingly for all the spanned regions.
 				 */
 				gvnh_spanreg_subs_gvt_init(gvnh_reg, gd_header, NULL);
 				maxi = gvspan->max_reg_index;
@@ -264,7 +312,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
 						gv_cur_region = reg;
 						change_reg();
 						gv_select_reg((void *)&ext_hash, freeze, reg_max_rec, reg_max_key,
-										reg_max_blk, restrict_reg, gvnh_reg, &gl_tail);
+									reg_max_blk, restrict_reg, gvnh_reg, &gl_tail);
 					}
 				}
 			}
@@ -282,6 +330,10 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
 	}
 	if (gmap_ptr_base != &gmap[0])
 		free(gmap_ptr_base);
+#	ifdef EXTRACT_HASHT_GLOBAL
+	if (NULL != hashgbl_gvnh_reg)
+		free(hashgbl_gvnh_reg);
+#	endif
 }
 
 /* Assumes "gv_target" and "gv_cur_region" are properly setup at function entry */
diff --git a/sr_port/gv_trigger_common.h b/sr_port/gv_trigger_common.h
index 0bf42d9..49ee3cc 100644
--- a/sr_port/gv_trigger_common.h
+++ b/sr_port/gv_trigger_common.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -39,35 +39,18 @@
 							&& (HASHT_GBL_CHAR1 == ADDR[1])			\
 							&& (HASHT_GBL_CHAR2 == ADDR[2]))
 
-#define	HASHT_GBL_CURLABEL	"2"	/* Currently supported ^#t global format */
+#define	HASHT_GBL_CURLABEL	"3"	/* 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 V21_HASHT_GBL_LABEL	"2"	/* V5.4-002 to V6.2-000 */
 
 #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
diff --git a/sr_port/gvcst_init.c b/sr_port/gvcst_init.c
index 077c324..a27882e 100644
--- a/sr_port/gvcst_init.c
+++ b/sr_port/gvcst_init.c
@@ -56,6 +56,7 @@
 #include "process_gvt_pending_list.h"
 #include "gvt_hashtab.h"
 #include "gtmmsg.h"
+#include "op.h"
 #ifdef UNIX
 #include "heartbeat_timer.h"
 #include "anticipatory_freeze.h"
@@ -68,6 +69,7 @@
 #include "gtm_dbjnl_dupfd_check.h"
 #endif
 
+GBLREF	boolean_t		mu_reorg_process;
 GBLREF	gd_region		*gv_cur_region, *db_init_region;
 GBLREF	sgmnt_data_ptr_t	cs_data;
 GBLREF	sgmnt_addrs		*cs_addrs;
@@ -100,7 +102,9 @@ GBLREF	boolean_t		pool_init;
 GBLREF	boolean_t		jnlpool_init_needed;
 GBLREF	jnlpool_addrs		jnlpool;
 #endif
-
+#ifdef DEBUG
+GBLREF	uint4			process_id;
+#endif
 LITREF char			gtm_release_name[];
 LITREF int4			gtm_release_name_len;
 
@@ -113,6 +117,9 @@ error_def(ERR_DBVERPERFWARN2);
 error_def(ERR_MMNODYNUPGRD);
 error_def(ERR_REGOPENFAIL);
 
+static readonly mval literal_poollimit =
+	DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, (SIZEOF("POOLLIMIT") - 1), "POOLLIMIT", 0, 0);
+
 void	assert_jrec_member_offsets(void)
 {
 	assert(REAL_JNL_HDR_LEN % DISK_BLOCK_SIZE == 0);
@@ -223,6 +230,7 @@ void gvcst_init(gd_region *greg)
 #	endif
 	int			max_fid_index;
 	mstr			log_nam, trans_log_nam;
+	mval			reg_nam_mval = DEFINE_MVAL_STRING(MV_STR, 0 , 0 , SIZEOF(MAX_RN_LEN), 0, 0, 0);
 	char			trans_buff[MAX_FN_LEN + 1];
 	unique_file_id		*greg_fid, *reg_fid;
 	tp_region		*tr;
@@ -325,6 +333,8 @@ void gvcst_init(gd_region *greg)
 	csa->hdr = NULL;
         csa->nl = NULL;
         csa->jnl = NULL;
+	csa->gbuff_limit = 0;
+	csa->our_midnite = 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;
@@ -638,7 +648,37 @@ void gvcst_init(gd_region *greg)
 			assert(0 == reformat_buffer_in_use);
 			--fast_lock_count;
 		}
-
+		assert(MV_STR & (TREF(gbuff_limit)).mvtype);
+		if (mu_reorg_process && (0 == (TREF(gbuff_limit)).str.len))
+		{	/* if the environment variable wasn't supplied, use the default for REORG */
+			(TREF(gbuff_limit)).str.len = SIZEOF(REORG_GBUFF_LIMIT);
+			(TREF(gbuff_limit)).str.addr = malloc(SIZEOF(REORG_GBUFF_LIMIT));
+			memcpy((TREF(gbuff_limit)).str.addr, REORG_GBUFF_LIMIT, SIZEOF(REORG_GBUFF_LIMIT));
+		}
+		if ((0 != (TREF(gbuff_limit)).str.len) PRO_ONLY(&& mu_reorg_process))	/* if reorg or dbg apply env var */
+		{
+			reg_nam_mval.str.len = greg->rname_len;
+			reg_nam_mval.str.addr = (char *)&greg->rname;
+			op_view(VARLSTCNT(3) &literal_poollimit, &reg_nam_mval, &(TREF(gbuff_limit)));
+#			ifdef DEBUG
+			if (!mu_reorg_process)		/* in dbg, randomize sizes to get test coverage */
+			{
+				if ((process_id & 1) ^ csa->regnum)
+				{
+					csa->gbuff_limit ^= process_id;
+					csa->gbuff_limit &= ((csd->n_bts / 2) - 1);
+				} else
+					csa->gbuff_limit = 0;
+			}
+			if (process_id & 2)		/* also randomize our_midnite */
+			{
+				csa->our_midnite = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets;
+				csa->our_midnite += (process_id & (csd->n_bts - 1));
+				assert((csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets + csd->n_bts)
+					> csa->our_midnite);
+			}
+#			endif
+		}
 	}
 	if ((dba_bg == greg_acc_meth) || (dba_mm == greg_acc_meth))
 	{
diff --git a/sr_port/hashtab.h b/sr_port/hashtab.h
index f4a8893..8c7029c 100644
--- a/sr_port/hashtab.h
+++ b/sr_port/hashtab.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -65,15 +65,33 @@
 		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.
-*/
-
+/* For string hashing, ELF hash was found to be the best during the V5.0-000 longnames project.
+ * During V6.2-001, Murmur3 hash was found to be much better than ELF in terms of # of collisions.
+ * So we are going with MMR hash for now in Unix. In VMS, we dont yet have mmrhash.c so we continue
+ * to use ELF hash there (no point spending time to move mmrhash.c from sr_unix to sr_port).
+ * In addition, the 32-bit murmur3 hash gives different values for the same input on different endian
+ * machines which would not work at least for triggers since we expect the trigger definition M code to
+ * hash to the same value on different endian machines (this is needed so mupip endiancvt does not need
+ * to worry about changing ^#t(.*TRHASH.*) nodes. Therefore we came up with a modified 32-bit murmur3 hash
+ * implementation that is endian independent (gtmmrhash_32).
+ */
+#ifdef UNIX
+#include "mmrhash.h"
+#define STR_HASH(KEY, LEN, HASH, SEED) gtmmrhash_32(KEY, LEN, SEED, (uint4 *)&HASH)
+/* The STR_PHASH* macros are the progressive variants of the STR_HASH macro. */
+#define	STR_PHASH_INIT(STATE, TOTLEN)			HASH128_STATE_INIT(STATE, 0); TOTLEN = 0
+#define	STR_PHASH_PROCESS(STATE, TOTLEN, KEY, LEN)	gtmmrhash_128_ingest(&STATE, KEY, LEN); TOTLEN += LEN
+#define	STR_PHASH_RESULT(STATE, TOTLEN, OUT4)			\
+{								\
+	gtm_uint16	out16;					\
+								\
+	gtmmrhash_128_result(&STATE, TOTLEN, &out16);		\
+	OUT4 = (uint4)out16.one;				\
+}
+#else
 #define STR_HASH ELF_HASH
+#endif
+
 #define ELF_HASH(sptr, len, hash, init_hashval)						\
 {											\
 	uint4	tempint;								\
@@ -89,61 +107,4 @@ We can remove them when we are certain that ELF_HASH is the best choice for us.
 	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
diff --git a/sr_port/have_crit.h b/sr_port/have_crit.h
index 5d5d57e..83baf05 100644
--- a/sr_port/have_crit.h
+++ b/sr_port/have_crit.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -188,6 +188,7 @@ GBLREF	boolean_t	deferred_timers_check_needed;
 
 #define	OK_TO_SEND_MSG	((INTRPT_IN_X_TIME_FUNCTION != intrpt_ok_state) 				\
 			&& (INTRPT_IN_LOG_FUNCTION != intrpt_ok_state)					\
+			&& (INTRPT_IN_FUNC_WITH_MALLOC != intrpt_ok_state)				\
 			&& (INTRPT_IN_FORK_OR_SYSTEM != intrpt_ok_state))
 
 uint4 have_crit(uint4 crit_state);
diff --git a/sr_port/indir.h b/sr_port/indir.h
index 573220b..9c14e7b 100644
--- a/sr_port/indir.h
+++ b/sr_port/indir.h
@@ -85,6 +85,6 @@ INDIR(indir_fndata,		f_data,		OC_FNDATA)
 ,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 */
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 ,INDIR(indir_zrupdate,		m_zrupdate,	0)
 #endif
diff --git a/sr_port/indirection.c b/sr_port/indirection.c
index be0b419..75ccac1 100644
--- a/sr_port/indirection.c
+++ b/sr_port/indirection.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -24,7 +24,7 @@ GBLREF	boolean_t	run_time;
 GBLREF	char		*lexical_ptr;
 GBLREF	spdesc		stringpool;
 GBLREF	unsigned char	*source_buffer;
-GBLREF	short int	source_column;
+GBLREF	int		source_column;
 
 error_def(ERR_BOOLSIDEFFECT);
 error_def(ERR_EXPR);
diff --git a/sr_port/io_rundown.c b/sr_port/io_rundown.c
index f703063..e8f375d 100644
--- a/sr_port/io_rundown.c
+++ b/sr_port/io_rundown.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -55,7 +55,7 @@ void io_dev_close (io_log_name *d)
 			return;
 	}
 
-	ESTABLISH(lastchance3);
+	VMS_ONLY(ESTABLISH(lastchance3);)
 	pp.mvtype = MV_STR;
 	pp.str.addr = (char *) p;
 	pp.str.len = SIZEOF(p);
@@ -63,5 +63,5 @@ void io_dev_close (io_log_name *d)
 		(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;
+	VMS_ONLY(REVERT;)
 }
diff --git a/sr_port/iosocket_close.c b/sr_port/iosocket_close.c
index 4347f8a..2629caa 100644
--- a/sr_port/iosocket_close.c
+++ b/sr_port/iosocket_close.c
@@ -37,6 +37,9 @@
 #include "iosocketdef.h"
 #include "stringpool.h"
 #include "eintr_wrappers.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
 
 GBLREF	io_desc		*active_device;
 GBLREF	int		process_exiting;
@@ -50,6 +53,7 @@ error_def(ERR_CLOSEFAIL);
 error_def(ERR_FILEOPENFAIL);
 error_def(ERR_SOCKNOTFND);
 error_def(ERR_SYSCALL);
+error_def(ERR_TLSIOERROR);
 
 void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boolean_t socket_delete, boolean_t socket_specified);
 
@@ -59,7 +63,7 @@ void iosocket_close(io_desc *iod, mval *pp)
 	unsigned char	ch;
 	int		handle_len;
 	d_socket_struct	*dsocketptr;
-	char		sock_handle[MAX_HANDLE_LEN];
+	char		sock_handle[MAX_HANDLE_LEN], *errp;
 	int4		start, end, index;
 	int		p_offset = 0;
 	boolean_t	socket_destroy = FALSE;
@@ -152,6 +156,7 @@ void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boole
 {
 	int4		ii,jj;
 	int		rc, save_fd, save_rc = 0, save_errno;
+	ssize_t		status;
 	socket_struct	*socketptr;
 #	ifndef VMS
 	struct stat	statbuf, fstatbuf;
@@ -182,6 +187,28 @@ void iosocket_close_range(d_socket_struct *dsocketptr, int start, int end, boole
 					LEN_AND_LIT("unlink during socket delete"), CALLFROM, errno);
 		}
 #		endif
+		/* below is similar to iosocket_flush but socketptr may not be current socket */
+		if (socketptr->obuffer_timer_set)
+		{
+			cancel_timer((TID)socketptr);
+			socketptr->obuffer_timer_set = FALSE;
+		}
+		status = 1;		/* OK value */
+		if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+		{
+			socketptr->obuffer_output_active = TRUE;
+			status = iosocket_output_buffer(socketptr);
+			socketptr->obuffer_output_active = FALSE;
+		}
+		if ((0 < socketptr->obuffer_size) && ((0 >= status) || (0 != socketptr->obuffer_errno)))
+			iosocket_buffer_error(socketptr);	/* pre-existing error or error flushing buffer */
+#ifdef		GTM_TLS
+		if (socketptr->tlsenabled)
+		{
+			gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+			socketptr->tlsenabled = FALSE;
+		}
+#endif
 		CLOSE(socketptr->sd, rc);
 		if (-1 == rc)
 		{
diff --git a/sr_port/iosocket_flush.c b/sr_port/iosocket_flush.c
index cb695c7..d4cace2 100644
--- a/sr_port/iosocket_flush.c
+++ b/sr_port/iosocket_flush.c
@@ -29,13 +29,14 @@ error_def(ERR_SOCKPASSDATAMIX);
 error_def(ERR_SOCKWRITE);
 error_def(ERR_TEXT);
 
+GBLREF	io_pair	io_std_device;
+
 void iosocket_flush(io_desc *iod)
 {
-#ifdef C9A06001531
-	/* pending change request C9A06001531 */
 
 	d_socket_struct	*dsocketptr;
 	socket_struct	*socketptr;
+	ssize_t		status;
 	int             on = 1, off = 0;
         char            *errptr;
         int4            errlen;
@@ -61,6 +62,25 @@ void iosocket_flush(io_desc *iod)
 		return;
 	}
 	ENSURE_DATA_SOCKET(socketptr);
+	if (socketptr->obuffer_timer_set)
+	{
+		cancel_timer((TID)socketptr);
+		socketptr->obuffer_timer_set = FALSE;
+	}
+	if (!socketptr->obuffer_output_active)
+	{	/* just to be safe */
+		status = 1;			/* OK value */
+		if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+		{
+			socketptr->obuffer_output_active = TRUE;
+			status = iosocket_output_buffer(socketptr);
+			socketptr->obuffer_output_active = FALSE;
+		}
+		if ((0 < socketptr->obuffer_size) && ((0 >= status) || (0 != socketptr->obuffer_errno)))
+			iosocket_buffer_error(socketptr);	/* pre-existing error or error flushing buffer */
+	}
+#ifdef C9A06001531
+	/* pending change request C9A06001531 */
         memcpy(iod->dollar.device, "0", SIZEOF("0"));
         if ( -1 == setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) ||
 		(-1 == setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &off, SIZEOF(off))))
diff --git a/sr_port/iosocket_iocontrol.c b/sr_port/iosocket_iocontrol.c
index 8e517a4..3dcb108 100644
--- a/sr_port/iosocket_iocontrol.c
+++ b/sr_port/iosocket_iocontrol.c
@@ -29,6 +29,7 @@
 
 GBLREF spdesc		stringpool;
 GBLREF io_pair		io_curr_device;
+LITREF	mval		skiparg;
 
 error_def(ERR_EXPR);
 error_def(ERR_INVCTLMNE);
@@ -46,6 +47,9 @@ void	iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
 	int		length, n, timeout;
 	pid_t		pid;
 	mval		*arg, *handlesvar = NULL;
+#ifdef	GTM_TLS
+	mval		*option, *tlsid, *password, *extraarg;
+#endif
 
 	if (0 == mn->len)
 		return;
@@ -59,9 +63,9 @@ void	iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
 		else
 		{
 			arg = va_arg(args, mval *);
-			if ((NULL == arg) || !MV_DEFINED(arg))
+			if ((NULL == arg) || M_ARG_SKIPPED(arg) || !MV_DEFINED(arg))
 			{
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_EXPR, 0);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
 				return;
 			}
 			depth = MV_FORCE_INTD(arg);
@@ -74,12 +78,13 @@ void	iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
 		else
 		{
 			arg = va_arg(args, mval *);
-			if ((NULL == arg) || !MV_DEFINED(arg))
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
+				timeout = MV_FORCE_INTD(arg);
+			else
 			{
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_EXPR, 0);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
 				return;
 			}
-			timeout = MV_FORCE_INTD(arg);
 		}
 		iosocket_wait(io_curr_device.in, timeout);
 #	ifndef VMS
@@ -90,48 +95,110 @@ void	iosocket_iocontrol(mstr *mn, int4 argcnt, va_list args)
 		{
 			arg = va_arg(args, mval *);
 			n--;
-			if ((NULL != arg) && MV_DEFINED(arg))
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
 				pid = MV_FORCE_INTD(arg);
 			else
 				pid = -1;
-		}
+		} else
+			pid = -1;
 		if (2 <= argcnt)
 		{
 			arg = va_arg(args, mval *);
 			n--;
-			if ((NULL != arg) && MV_DEFINED(arg))
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
 				timeout = MV_FORCE_INTD(arg);
 			else
 				timeout = NO_M_TIMEOUT;
-		}
+		} else
+			timeout = NO_M_TIMEOUT;
 		iosocket_pass_local(io_curr_device.out, pid, timeout, n, args);
 	} else if (0 == memcmp(action, "ACCEPT", length))
 	{
 		n = argcnt;
 		if (1 <= argcnt)
 		{
-			handlesvar = va_arg(args, mval *);
+			arg = va_arg(args, mval *);
 			n--;
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg))
+				handlesvar = arg;
 		}
 		if (2 <= argcnt)
 		{
 			arg = va_arg(args, mval *);
 			n--;
-			if ((NULL != arg) && MV_DEFINED(arg))
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
 				pid = MV_FORCE_INTD(arg);
 			else
 				pid = -1;
-		}
+		} else
+			pid = -1;
 		if (3 <= argcnt)
 		{
 			arg = va_arg(args, mval *);
 			n--;
-			if ((NULL != arg) && MV_DEFINED(arg))
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
 				timeout = MV_FORCE_INTD(arg);
 			else
 				timeout = NO_M_TIMEOUT;
-		}
+		} else
+			timeout = NO_M_TIMEOUT;
 		iosocket_accept_local(io_curr_device.in, handlesvar, pid, timeout, n, args);
+#ifdef	GTM_TLS
+	} else if (0 == memcmp(action, "TLS", length))
+	{	/*	WRITE /TLS(option[,[timeout][,tlsid[,password]]]) */
+		if (1 <= argcnt)
+		{
+			option = va_arg(args, mval *);
+			if ((NULL != option) && !M_ARG_SKIPPED(option) && MV_DEFINED(option))
+				MV_FORCE_STRD(option);
+			else
+			{
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
+				return;
+			}
+		} else
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXPR);
+			return;
+		}
+		if (2 <= argcnt)
+		{
+			arg = va_arg(args, mval *);
+			if ((NULL != arg) && !M_ARG_SKIPPED(arg) && MV_DEFINED(arg))
+				timeout = MV_FORCE_INTD(arg);
+			else
+				timeout = NO_M_TIMEOUT;
+		} else
+			timeout = NO_M_TIMEOUT;
+		if (3 <= argcnt)
+		{
+			tlsid = va_arg(args, mval *);
+			if ((NULL != tlsid) && !M_ARG_SKIPPED(tlsid) && MV_DEFINED(tlsid))
+				MV_FORCE_STRD(tlsid);
+			else
+				tlsid = NULL;
+		} else
+			tlsid = NULL;
+		if ((4 <= argcnt) && (NULL != tlsid))
+		{	/* password only valid if tlsid provided */
+			password = va_arg(args, mval *);
+			if ((NULL != password) && !M_ARG_SKIPPED(password) && MV_DEFINED(password))
+				MV_FORCE_STRD(password);
+			else
+				password = NULL;
+		} else
+			password = NULL;
+		if (5 <= argcnt)
+		{
+			extraarg = va_arg(args, mval *);
+			if ((NULL != extraarg) && !M_ARG_SKIPPED(extraarg) && MV_DEFINED(extraarg))
+				MV_FORCE_STRD(extraarg);
+			else
+				extraarg = NULL;
+		} else
+			extraarg = NULL;
+		iosocket_tls(option, timeout, tlsid, password, extraarg);
+#	endif
 #	endif
 	} else
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE);
diff --git a/sr_port/iosocket_readfl.c b/sr_port/iosocket_readfl.c
index d1e1fdf..eaa9fc2 100644
--- a/sr_port/iosocket_readfl.c
+++ b/sr_port/iosocket_readfl.c
@@ -40,6 +40,9 @@
 #include "send_msg.h"
 #include "error.h"
 #include "trace_table.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
 
 GBLREF	stack_frame      	*frame_pointer;
 GBLREF	unsigned char    	*stackbase, *stacktop, *msp, *stackwarn;
@@ -127,7 +130,7 @@ int	iosocket_readfl(mval *v, int4 width, int4 timeout)
 	int		ret, byteperchar;
 	boolean_t 	timed, vari, more_data, terminator, has_delimiter, requeue_done, do_delim_conv, need_get_chset;
 	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		flags, len, real_errno, save_errno, fcntl_res, errlen, devlen, 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;
@@ -889,9 +892,17 @@ int	iosocket_readfl(mval *v, int4 width, int4 timeout)
 		iod->dollar.za = 9;
 		len = SIZEOF(ONE_COMMA) - 1;
 		memcpy(iod->dollar.device, ONE_COMMA, len);
-		errptr = (char *)STRERROR(real_errno);
+#ifdef		GTM_TLS
+		if (socketptr->tlsenabled && (0 > real_errno))
+			errptr = (char *)gtm_tls_get_error();
+		else	/* TLS not enabled or system call error */
+#endif
+			errptr = (char *)STRERROR(real_errno);
 		errlen = STRLEN(errptr);
-		memcpy(&iod->dollar.device[len], errptr, errlen + 1);	/* + 1 for null */
+                devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+                memcpy(&iod->dollar.device[len], errptr, devlen + 1);
+                if (devlen < errlen)
+                        iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
 #		ifdef UNIX
 		if (io_curr_device.in == io_std_device.in)
 		{
diff --git a/sr_port/iosocket_snr.c b/sr_port/iosocket_snr.c
index 9ed6573..579db52 100644
--- a/sr_port/iosocket_snr.c
+++ b/sr_port/iosocket_snr.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -62,6 +62,9 @@ static int fcntl_res;
 #include "min_max.h"
 #include "gtm_utf8.h"
 #include "outofband.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
 
 /* 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.
@@ -77,6 +80,9 @@ GBLREF	io_pair 		io_curr_device;
 GBLREF	bool			out_of_time;
 GBLREF	spdesc 			stringpool;
 GBLREF	int4			outofband;
+#ifdef GTM_TLS
+GBLREF	gtm_tls_ctx_t		*tls_ctx;
+#endif
 
 /* 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);
@@ -145,13 +151,19 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i
  */
 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;
-	struct timeval	lcl_time_for_read;
+	int		status, real_errno;
+	ssize_t		bytesread;
+	boolean_t	pollread;
 #	ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
 	long		poll_timeout;
 	unsigned long	poll_nfds;
 	struct pollfd	poll_fdlist[1];
+#	else
+	fd_set		tcp_fd, *readfds, *writefds;
+	struct timeval	lcl_time_for_read;
+#	endif
+#	ifdef GTM_TLS
+	int		tlspolldirection = 0;
 #	endif
 
 	DBGSOCK2((stdout, "socsnrio: Socket read request - socketptr: 0x"lvaddr"  buffer: 0x"lvaddr"  maxlength: %d  flags: %d  ",
@@ -161,36 +173,92 @@ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength
 #ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
 	assertpro(FD_SETSIZE > socketptr->sd);
 	FD_ZERO(&tcp_fd);
-	FD_SET(socketptr->sd, &tcp_fd);
-	assert(0 != FD_ISSET(socketptr->sd, &tcp_fd));
-	lcl_time_for_read.tv_sec = time_for_read->at_sec;
-	lcl_time_for_read.tv_usec = (gtm_tv_usec_t) time_for_read->at_usec;
-	status = 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)
+	while (TRUE)
 	{
-                RECV(socketptr->sd, buffer, maxlength, flags, bytesread);
-		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;
+		status = 0;
+#		ifdef GTM_TLS
+		if (socketptr->tlsenabled)
+		{
+			pollread = (tlspolldirection == GTMTLS_WANT_WRITE) ? FALSE : TRUE;
+			status = gtm_tls_cachedbytes((gtm_tls_socket_t *)socketptr->tlssocket);
+		} else
+#		endif
+			pollread = TRUE;
+		if (0 == status)
+		{	/* if TLS cachedbytes available no need to poll */
+#			ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
+			FD_SET(socketptr->sd, &tcp_fd);
+			assert(0 != FD_ISSET(socketptr->sd, &tcp_fd));
+			lcl_time_for_read.tv_sec = time_for_read->at_sec;
+			lcl_time_for_read.tv_usec = (gtm_tv_usec_t)time_for_read->at_usec;
+			if (pollread)
+			{
+				readfds = &tcp_fd;
+				writefds = NULL;
+			} else
+			{
+				writefds = &tcp_fd;
+				readfds = NULL;
+			}
+			status = select(socketptr->sd + 1, readfds, writefds, NULL, &lcl_time_for_read);
+#			else
+			poll_fdlist[0].fd = socketptr->sd;
+			poll_fdlist[0].events = pollread ? POLLIN : POLLOUT;
+			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)
+		{
+#			ifdef GTM_TLS
+			if (socketptr->tlsenabled)
+			{
+				bytesread = gtm_tls_recv((gtm_tls_socket_t *)socketptr->tlssocket, buffer, maxlength);
+				if (0 < bytesread)
+					return bytesread;
+				/* if want read or write, need to loop */
+				/* after setting tlspolldirection */
+				switch (bytesread)
+				{
+					case GTMTLS_WANT_READ:
+						tlspolldirection = GTMTLS_WANT_READ;
+						break;
+					case GTMTLS_WANT_WRITE:
+						tlspolldirection = GTMTLS_WANT_WRITE;
+						break;
+					default:
+						socketptr->last_recv_errno = errno = gtm_tls_errno();
+						if (ECONNRESET == errno)
+						{
+							return (ssize_t)(-2);
+						} else
+							return (ssize_t)(-1);
+				}
+				continue;
+			} else
+#			endif
+			{
+				RECV(socketptr->sd, buffer, maxlength, flags, bytesread);
+				real_errno = errno;
+				socketptr->last_recv_errno = (-1 != status) ? 0 : real_errno;	/* Save status for dbg 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;
+			}
+		} else
+			break;		/* nothing ready */
 	}
 	DBGSOCK_ONLY2(errno = real_errno);
 	return (ssize_t)status;
@@ -266,8 +334,8 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
 			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 */
+			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
@@ -281,7 +349,7 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
 			{
 				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 */
+					mblen = 1;	/* If buffer is too small we will get -1 here. Assume need 2 chars */
 			}
 			break;
 		default:
@@ -314,7 +382,7 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f
 			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. */
+			{	/* Some error occurred. Check for restartable condition. */
 				if (EINTR == errno)
 					if (!out_of_time)
 						continue;
diff --git a/sr_port/iosocket_use.c b/sr_port/iosocket_use.c
index 2ed9c33..2753ea1 100644
--- a/sr_port/iosocket_use.c
+++ b/sr_port/iosocket_use.c
@@ -90,6 +90,7 @@ void	iosocket_use(io_desc *iod, mval *pp)
 		        bfsize_specified = FALSE,
 		        ibfsize_specified = FALSE,
 		        moreread_specified = FALSE,
+		        flush_specified = FALSE,
 		        create_new_socket;
 	int4 		index, n_specified, zff_len, delimiter_len, moreread_timeout;
 	int		fil_type, nodelay, p_offset = 0;
@@ -306,6 +307,10 @@ void	iosocket_use(io_desc *iod, mval *pp)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
                                 moreread_specified = TRUE;
                                 break;
+			case iop_flush:
+				n_specified++;
+				flush_specified = TRUE;
+				break;
 			default:
 				/* ignore deviceparm */
 				break;
@@ -495,6 +500,8 @@ void	iosocket_use(io_desc *iod, mval *pp)
 	if (!create_new_socket)
 	{
 		/* these changes apply to only pre-existing sockets */
+		if (flush_specified)
+			iosocket_flush(iod);	/* buffered output if any */
 		if (bfsize_specified)
 			newsocket.buffer_size = bfsize;
 #ifdef TCP_NODELAY
diff --git a/sr_port/iosocket_wait.c b/sr_port/iosocket_wait.c
index 2ca1921..9774e3a 100644
--- a/sr_port/iosocket_wait.c
+++ b/sr_port/iosocket_wait.c
@@ -208,28 +208,31 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 		}
 		if (nselect)
 		{
-			utimeout.tv_sec = timepar;
-			utimeout.tv_usec = 0;
-			msec_timeout = timeout2msec(timepar);
-			sys_get_curr_time(&cur_time);
-			if (!retry_accept && (!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.  Or retry after failed accept.
-				*/
-				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;
+			if (NO_M_TIMEOUT != timepar)
+			{
+				utimeout.tv_sec = timepar;
+				utimeout.tv_usec = 0;
+				msec_timeout = timeout2msec(timepar);
+				sys_get_curr_time(&cur_time);
+				if (!retry_accept && (!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.  Or retry after failed accept.
+					*/
+					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;
+					}
 				}
 			}
 			zint_restart = sockintr->end_time_valid = FALSE;
@@ -265,8 +268,12 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 							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;
+							if (NO_M_TIMEOUT != timepar)
+							{
+								sockintr->end_time = end_time;
+								sockintr->end_time_valid = TRUE;
+							} else
+								sockintr->end_time_valid = FALSE;
 							dsocketptr->mupintr = TRUE;
 							socketus_interruptus++;
 							DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d"
@@ -277,15 +284,18 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 						assertpro(FALSE);      /* 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)
+					if (NO_M_TIMEOUT != timepar)
 					{
-						rv = 0;		/* time out */
-						break;
+						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;
 					}
-					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 */
 			}
@@ -293,8 +303,11 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 			{	/* none selected or prior pending event */
 				iod->dollar.key[0] = '\0';
 				if (NO_M_TIMEOUT != timepar)
+				{
 					dollar_truth = FALSE;
-				return FALSE;
+					return FALSE;
+				} else
+					continue;
 			} else  if (rv < 0)
 			{
 				errptr = (char *)STRERROR(errno);
@@ -306,8 +319,11 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 		{	/* nothing to select and no pending events */
 			iod->dollar.key[0] = '\0';
 			if (NO_M_TIMEOUT != timepar)
+			{
 				dollar_truth = FALSE;
-			return FALSE;
+				return FALSE;
+			} else
+				continue;
 		}
 		/* find out which sockets are ready */
 		oldestlistencycle = oldestconnectedcycle = oldesteventcycle = 0;
@@ -324,7 +340,7 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 					break;
 			}
 			assertpro((0 == jj) || (jj <= poll_nfds));	/* equal poll_nfds if not polled */
-			if (nselect && (jj != poll_nfds) && (socketptr->sd == poll_fds[jj].fd) && (poll_fds[jj].revents & POLLIN))
+			if (nselect && (jj != poll_nfds) && (socketptr->sd == poll_fds[jj].fd) && poll_fds[jj].revents)
 #endif
 #ifdef USE_SELECT
 			assertpro(FD_SETSIZE > socketptr->sd);
@@ -374,7 +390,16 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
 			oldesteventcycle = oldestconnectedcycle;
 			oldesteventindex = oldestconnectedindex;
 		} else
-			assertpro((0 < oldestlistencycle) || (0 < oldestconnectedcycle));
+		{	/* unexpected nothing to do */
+			assert((0 < oldestlistencycle) || (0 < oldestconnectedcycle));
+			iod->dollar.key[0] = '\0';
+			if (NO_M_TIMEOUT != timepar)
+			{
+				dollar_truth = FALSE;
+				return FALSE;
+			} else
+				continue;
+		}
 		socketptr = dsocketptr->socket[oldesteventindex];
 		socketptr->pendingevent = FALSE;
 		if (socket_listening == socketptr->state)
diff --git a/sr_port/iosocket_write.c b/sr_port/iosocket_write.c
index 03c9ba4..4c53402 100644
--- a/sr_port/iosocket_write.c
+++ b/sr_port/iosocket_write.c
@@ -14,6 +14,11 @@
 #include "mdef.h"
 
 #include <errno.h>
+#ifdef USE_POLL
+#include <poll.h>
+#else
+#include "gtm_select.h"
+#endif
 #include "gtm_socket.h"
 #include "gtm_inet.h"
 #include "gtm_stdio.h"
@@ -26,9 +31,14 @@
 #include "dollarx.h"
 #include "gtm_conv.h"
 #include "gtm_utf8.h"
+#include "min_max.h"
 #include "stringpool.h"
 #include "send_msg.h"
 #include "error.h"
+#include "rel_quant.h"
+#ifdef GTM_TLS
+#include "gtm_tls.h"
+#endif
 
 GBLREF io_pair			io_curr_device;
 #ifdef UNIX
@@ -39,6 +49,9 @@ GBLREF bool			prin_out_dev_failure;
 GBLREF mstr			chset_names[];
 GBLREF UConverter		*chset_desc[];
 GBLREF spdesc			stringpool;
+#ifdef GTM_TLS
+GBLREF	gtm_tls_ctx_t		*tls_ctx;
+#endif
 
 error_def(ERR_CURRSOCKOFR);
 error_def(ERR_DELIMSIZNA);
@@ -47,10 +60,11 @@ error_def(ERR_NOSOCKETINDEV);
 error_def(ERR_SOCKPASSDATAMIX);
 error_def(ERR_SOCKWRITE);
 error_def(ERR_TEXT);
+UNIX_ONLY(error_def(ERR_TLSIOERROR);)
 error_def(ERR_ZFF2MANY);
 error_def(ERR_ZINTRECURSEIO);
 
-#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC)									\
+#define DOTCPSEND_REAL(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC)								\
 {															\
 	ssize_t		gtmioStatus;											\
 	size_t		gtmioBuffLen;											\
@@ -62,7 +76,7 @@ error_def(ERR_ZINTRECURSEIO);
 	for (;;)													\
         {														\
 		gtmioChunk = gtmioBuffLen VMS_ONLY(> VMS_MAX_TCP_IO_SIZE ? VMS_MAX_TCP_IO_SIZE : gtmioBuffLen);		\
-		SEND(SDESC, gtmioBuff, gtmioChunk, SFLAGS, gtmioStatus);						\
+		SEND((SOCKETPTR)->sd, gtmioBuff, gtmioChunk, SFLAGS, gtmioStatus);					\
 		if ((ssize_t)-1 != gtmioStatus)										\
 	        {													\
 			gtmioBuffLen -= gtmioStatus;									\
@@ -81,11 +95,280 @@ error_def(ERR_ZINTRECURSEIO);
 		RC = -1;		/* Something kept us from sending what we wanted */				\
 }
 
+#define DOTCPSEND(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC)								\
+{															\
+	ssize_t	localstatus;													\
+	if (0 == (SOCKETPTR)->obuffer_size)										\
+		DOTCPSEND_REAL(SOCKETPTR, SBUFF, SBUFF_LEN, SFLAGS, RC)							\
+	else														\
+	{														\
+		localstatus = iosocket_write_buffered(SOCKETPTR, SBUFF, SBUFF_LEN);						\
+		if (SBUFF_LEN == localstatus)										\
+			RC = 0;												\
+		else													\
+			RC = -1;											\
+	}														\
+}
+
 void	iosocket_write(mstr *v)
 {
 	iosocket_write_real(v, TRUE);
 }
 
+void iosocket_buffer_error(socket_struct *socketptr)
+{	/* output error from obuffer_errno */
+	int		errlen, devlen, save_obuffer_errno;
+	io_desc		*iod;
+	d_socket_struct	*dsocketptr;
+	const char	*errptr;
+
+	if (0 == socketptr->obuffer_errno)
+		return;			/* no error */
+	dsocketptr = socketptr->dev;
+	iod = dsocketptr->iod;
+#	ifdef GTM_TLS
+	if (socketptr->tlsenabled)
+	{
+		iod->dollar.za = 9;
+		memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA));
+		if (-1 == socketptr->obuffer_errno)
+			errptr = gtm_tls_get_error();
+		else
+			errptr = (char *)STRERROR(socketptr->obuffer_errno);
+		errlen = STRLEN(errptr);
+		devlen = MIN((SIZEOF(iod->dollar.device) - SIZEOF(ONE_COMMA)), errlen);
+		memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, devlen);
+		if (devlen < errlen)
+			iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+		socketptr->obuffer_errno = 0;
+		if (socketptr->ioerror)
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TLSIOERROR, 2, LEN_AND_LIT("send"),
+				ERR_TEXT, 2, errlen, errptr);
+	} else
+#	endif
+	{
+		save_obuffer_errno = socketptr->obuffer_errno;
+		socketptr->obuffer_errno = 0;
+		SOCKERROR(iod, socketptr, ERR_SOCKWRITE, save_obuffer_errno);
+	}
+}
+
+ssize_t iosocket_output(socket_struct *socketptr, char *buffer, size_t length, boolean_t resetbuffer, boolean_t timed);
+
+ssize_t iosocket_output(socket_struct *socketptr, char *buffer, size_t length, boolean_t resetbuffer, boolean_t timed)
+{
+	boolean_t	pollwrite;
+	ssize_t		status;
+	size_t		llen;
+	int		bytessent, istatus, timeout, save_errno;
+	char		*lbuffer;
+#	ifdef GTM_TLS
+	int		tlspolldirection = 0;
+#	endif
+#	ifdef USE_POLL
+	struct pollfd	fds;
+#	else
+	fd_set		fds, *readfds, *writefds;
+	struct timeval	timeout_spec;
+#	endif
+
+	if (!socketptr->obuffer_output_active)
+		return 0;		/* how did we get here */
+	if (timed)
+	{
+		if (0 != socketptr->obuffer_errno)
+			return -1;	/* unprocessed error */
+		timeout = 0;		/* no waiting in poll */
+	} else
+		timeout = socketptr->obuffer_wait_time;
+#	ifndef USE_POLL
+	FD_ZERO(&fds);
+	FD_SET(socketptr->sd, &fds);
+	timeout = timeout * 1000;	/* convert milli to micro seconds */
+	timeout_spec.tv_sec = 0;
+	timeout_spec.tv_usec = timeout;
+#	endif
+	llen = length;
+	lbuffer = buffer;
+	while (0 < llen)
+	{	/* poll/select tlspolldirection - needed if noblocking */
+#		ifdef GTM_TLS
+		if (socketptr->tlsenabled)
+			pollwrite = (tlspolldirection == GTMTLS_WANT_READ) ? FALSE : TRUE;
+		else
+#		endif
+			pollwrite = TRUE;
+#		ifdef USE_POLL
+		fds.fd = socketptr->sd;
+		fds.events = pollwrite ? POLLOUT : POLLIN;
+		istatus = poll(&fds, 1, timeout);
+#		else
+		if (pollwrite)
+		{
+			writefds = &fds;
+			readfds = NULL;
+		} else
+		{
+			readfds = &fds;
+			writefds = NULL;
+		}
+		istatus = select(socketptr->sd + 1, readfds, writefds, NULL, &timeout_spec);
+#		endif
+		if (-1 == istatus)
+		{
+			save_errno = errno;
+			if (timed)
+			{	/* called from timer so only try once */
+				socketptr->obuffer_errno = save_errno;
+				status = -1;
+				break;
+			}
+			if (EAGAIN == save_errno)
+				rel_quant();
+			else if (EINTR != save_errno)
+			{
+				status = -1;
+				break;
+			}
+#			ifndef USE_POLL
+			timeout_spec.tv_usec = timeout;
+			FD_SET(socketptr->sd, &fds);
+#			endif
+			continue;
+		}
+#		ifdef GTM_TLS
+		if (socketptr->tlsenabled)
+		{
+			bytessent = gtm_tls_send((gtm_tls_socket_t *)socketptr->tlssocket, lbuffer, llen);
+			if (0 < bytessent)
+			{	/* unless partial writes enabled either none or all should have been written */
+				llen -= bytessent;
+				lbuffer += bytessent;
+				tlspolldirection = 0;
+			} else
+			{
+				switch (bytessent)
+				{
+					case GTMTLS_WANT_READ:
+						tlspolldirection = GTMTLS_WANT_READ;
+						break;
+					case GTMTLS_WANT_WRITE:
+						tlspolldirection = GTMTLS_WANT_WRITE;
+						break;
+					default:
+						assert(-1 == bytessent);
+						socketptr->obuffer_errno = gtm_tls_errno();
+						if (ECONNRESET == socketptr->obuffer_errno)
+						{
+							return (ssize_t)(-2);
+						} else
+							return (ssize_t)(-1);
+				}
+			}
+			if (0 == llen)
+				status = length;
+			else
+				status = 0;
+		} else
+#		endif
+		{
+			DOTCPSEND_REAL(socketptr, buffer, length, 0, status);
+			if (0 != status)
+			{	/* current callers do this check and return */
+				/* if timed, just return - maybe set flag in struct */
+				socketptr->obuffer_errno = status;
+				status = -1;
+			} else
+				status = length;
+			break;
+		}
+	}
+	if (status == length)
+	{
+		socketptr->obuffer_errno = 0;
+		if (resetbuffer)
+			socketptr->obuffer_length = socketptr->obuffer_offset = 0;
+	}
+	return status;
+}
+
+/*	prototype in iosocketdef.h since called by iosocket_flush and iosocket_close */
+ssize_t iosocket_output_buffer(socket_struct *socketptr)
+{
+	ssize_t	status;
+	status = iosocket_output(socketptr, socketptr->obuffer, socketptr->obuffer_length, TRUE, FALSE);
+	return status;
+}
+
+void iosocket_output_timed(socket_struct *socketptr);
+
+void iosocket_output_timed(socket_struct *socketptr)
+{
+	ssize_t	status;
+	size_t	length;
+
+	socketptr->obuffer_timer_set = FALSE;
+	if (!socketptr->obuffer_output_active && (0 < socketptr->obuffer_length))
+	{	/* no current writer so output the buffer */
+		socketptr->obuffer_output_active = TRUE;
+		length = socketptr->obuffer_length;
+		status = iosocket_output(socketptr, socketptr->obuffer, length, TRUE, TRUE);
+		socketptr->obuffer_output_active = FALSE;
+	}
+	/* reschedule timer if needed */
+	if ((0 < socketptr->obuffer_length) && (0 == socketptr->obuffer_errno))
+	{
+		socketptr->obuffer_timer_set = TRUE;
+		start_timer((TID)socketptr, socketptr->obuffer_flush_time, iosocket_output_timed,
+			SIZEOF(socketptr), (char *)&socketptr);
+	}
+}
+
+ssize_t	iosocket_write_buffered(socket_struct *socketptr, char *buffer, size_t length);
+ssize_t	iosocket_write_buffered(socket_struct *socketptr, char *buffer, size_t length)
+{
+	ssize_t		status, obuffered_len;
+	int		errlen, devlen;
+	io_desc		*iod;
+	d_socket_struct	*dsocketptr;
+	const char	*errptr;
+
+	socketptr->obuffer_output_active = TRUE;	/* lock out timed writes */
+	status = (0 != socketptr->obuffer_errno) ? -1 : 0;
+	if ((0 == status ) && (0 < socketptr->obuffer_length) && ((socketptr->obuffer_size - socketptr->obuffer_length) <= length))
+	{	/* more output than space left in buffer */
+		obuffered_len = socketptr->obuffer_length;
+		status = iosocket_output_buffer(socketptr);
+		if (obuffered_len == status)
+			status = 0;			/* success */
+	}
+	if ((0 == status ) && (length > socketptr->obuffer_size))
+	{	/* more output than can fit in buffer so just output it now */
+		status = iosocket_output(socketptr, buffer, length, FALSE, FALSE);
+		if (status == length)
+			status = 0;			/* success */
+	} else if (0 == status)
+	{	/* put in buffer since room is available */
+		memcpy((void *)(socketptr->obuffer + socketptr->obuffer_offset), buffer, length);
+		socketptr->obuffer_offset += length;
+		socketptr->obuffer_length += length;
+		status = length;
+		/* start timer if not active */
+		if (!socketptr->obuffer_timer_set)
+		{
+			socketptr->obuffer_timer_set = TRUE;
+			start_timer((TID)socketptr, socketptr->obuffer_flush_time, iosocket_output_timed,
+				SIZEOF(socketptr), (char *)&socketptr);
+		}
+	}
+	socketptr->obuffer_output_active = FALSE;
+	if (0 > status)
+	{	/* report error */
+		iosocket_buffer_error(socketptr);
+	}
+	return status;
+}
+
 void	iosocket_write_real(mstr *v, boolean_t convert_output)
 {
 	io_desc		*iod;
@@ -136,7 +419,7 @@ void	iosocket_write_real(mstr *v, boolean_t convert_output)
 			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);
+			DOTCPSEND(socketptr, UTF16BE_BOM, UTF16BE_BOM_LEN, flags, status);
 			DBGSOCK2((stdout, "socwrite: TCP send of BOM-BE with rc %d\n", status));
 			if (0 != status)
 			{
@@ -229,7 +512,7 @@ void	iosocket_write_real(mstr *v, boolean_t convert_output)
 					 * there will be recursion iosocket_Write -> iosocket_Wteol ->iosocket_Write */
 					if (0 < socketptr->n_delimiter)
 					{
-						DOTCPSEND(socketptr->sd, socketptr->odelimiter0.addr, socketptr->odelimiter0.len,
+						DOTCPSEND(socketptr, 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));
@@ -271,7 +554,7 @@ void	iosocket_write_real(mstr *v, boolean_t convert_output)
 				}
 			}
 			assert(0 != b_len);
-			DOTCPSEND(socketptr->sd, out, b_len, (socketptr->urgent ? MSG_OOB : 0) | flags, status);
+			DOTCPSEND(socketptr, 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)
 			{
diff --git a/sr_port/iosocketdef.h b/sr_port/iosocketdef.h
index 90ec294..4983414 100644
--- a/sr_port/iosocketdef.h
+++ b/sr_port/iosocketdef.h
@@ -90,6 +90,8 @@ typedef struct
 #define INITIAL_MOREREAD_TIMEOUT	200
 #define DEFAULT_MOREREAD_TIMEOUT	10
 #define MAX_MOREREAD_TIMEOUT		999
+/* For buffered output, wait this long for socket to be ready to output */
+#define DEFAULT_WRITE_WAIT		200
 
 #define	ONE_COMMA			"1,"
 
@@ -327,7 +329,7 @@ typedef struct socket_struct_type
 	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 */
+	char				*buffer;			/* pointer to the buffer of this socket */
 	boolean_t			nodelay;
 	boolean_t			first_read;
 	boolean_t			first_write;
@@ -345,6 +347,23 @@ typedef struct socket_struct_type
 	boolean_t			pendingevent;		/* if listening, needs accept */
 	enum socket_creator		howcreated;
 	char				*parenthandle;		/* listening socket this created from */
+	size_t				obuffer_size;		/* size of the output buffer for this socket */
+	size_t				obuffer_length;		/* length of output in this buffer */
+	size_t				obuffer_offset;		/* offset of the buffered output to buffer head */
+	volatile boolean_t		obuffer_timer_set;	/* timer scheduled to flush buffer */
+	volatile boolean_t		obuffer_output_active;	/* in buffer output now */
+	int				obuffer_flush_time;	/* flush output buffer after this many milliseconds */
+	int				obuffer_wait_time;	/* wait for output ready this many milliseconds */
+	int				obuffer_errno;		/* save status from timed output attempt */
+	char				*obuffer;		/* pointer to the output buffer of this socket */
+	boolean_t			nonblocking;		/* socket has been set O_NONBLOCK */
+#ifdef GTM_TLS
+	boolean_t			tlsenabled;
+	void				*tlssocket;		/* actually gtm_tls_socket_t */
+	boolean_t			tlsreadblocked;
+	boolean_t			tlswriteblocked;
+	short				tlspolldirection;	/* what TLS wants */
+#endif
 } socket_struct;
 
 typedef struct socket_interrupt_type
@@ -389,4 +408,9 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned
 boolean_t iosocket_listen_sock(socket_struct *socketptr, unsigned short len);
 void iosocket_close_one(d_socket_struct *dsocketptr, int index);
 int iosocket_accept(d_socket_struct *dsocketptr, socket_struct *socketptr, boolean_t selectfirst);
+ssize_t iosocket_output_buffer(socket_struct *socketptr);
+void iosocket_buffer_error(socket_struct *socketptr);
+#ifdef GTM_TLS
+void    iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg);
+#endif
 #endif
diff --git a/sr_port/jnl.h b/sr_port/jnl.h
index 3334020..200656e 100644
--- a/sr_port/jnl.h
+++ b/sr_port/jnl.h
@@ -54,8 +54,8 @@ error_def(ERR_JNLENDIANLITTLE);
  * 		which needs to change to say IF_curTO17 if the earliest supported version changes to V17 or so).
  *
  */
-#define JNL_LABEL_TEXT		"GDSJNL24"	/* see above comment paragraph for todos whenever this is changed */
-#define JNL_VER_THIS		24
+#define JNL_LABEL_TEXT		"GDSJNL25"	/* see above comment paragraph for todos whenever this is changed */
+#define JNL_VER_THIS		25
 #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
@@ -67,11 +67,11 @@ error_def(ERR_JNLENDIANLITTLE);
 						 */
 #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.
+#define JRT_MAX_V22		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 JRT_MAX_V24		JRT_ULGTRIG	/* Max jnlrec type in GDSJNL22/GDSJNL23 that can be input to replication filter */
+#define JRT_MAX_V24		JRT_ULGTRIG	/* Max jnlrec type in GDSJNL24/GDSJNL25 that can be input to replication filter */
 
 #ifdef UNIX
 #  define JNL_ALLOC_DEF		2048
@@ -297,40 +297,30 @@ error_def(ERR_JNLENDIANLITTLE);
 
 #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;									\
+		STATUS = ERR_JNLBADLABEL;								\
+		if (DO_GTMPUTMSG)									\
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) STATUS, 6, JNL_FN_LEN, JNL_FN,	\
+				LEN_AND_LIT(JNL_LABEL_TEXT), SIZEOF((JFH)->label), (JFH)->label);	\
 	}												\
 	BIGENDIAN_ONLY(											\
 	else if ((JFH)->is_little_endian)								\
 	{												\
-		lcl_status = ERR_JNLENDIANLITTLE;							\
-		check_failed = TRUE;									\
+		STATUS = ERR_JNLENDIANLITTLE;								\
+		if (DO_GTMPUTMSG)									\
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) STATUS, 2, JNL_FN_LEN, JNL_FN);	\
 	}												\
 	)												\
 	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;									\
+		STATUS = ERR_JNLENDIANBIG;								\
 		if (DO_GTMPUTMSG)									\
-			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) lcl_status, 2, JNL_FN_LEN, JNL_FN);	\
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) STATUS, 2, JNL_FN_LEN, JNL_FN);	\
 	}												\
+	)												\
 }
 
 /* Token generation used in non-replicated journaled environment. Note the assumption here
diff --git a/sr_port/jnl_file_open_common.c b/sr_port/jnl_file_open_common.c
index 2dbcae2..56e9c05 100644
--- a/sr_port/jnl_file_open_common.c
+++ b/sr_port/jnl_file_open_common.c
@@ -239,7 +239,8 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
 	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(4 == SIZEOF(header->alignsize));	/* so we can use the 32bit version of ceil_log2 */
+	jb->log2_of_alignsize = ceil_log2_32bit(header->alignsize);
 	assert(header->autoswitchlimit == csd->autoswitchlimit);
 	assert(header->jnl_alq == csd->jnl_alq);
 	assert(header->jnl_deq == csd->jnl_deq);
diff --git a/sr_port/jnl_file_open_switch.c b/sr_port/jnl_file_open_switch.c
index f3d644d..8cff125 100644
--- a/sr_port/jnl_file_open_switch.c
+++ b/sr_port/jnl_file_open_switch.c
@@ -40,14 +40,19 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts)
 	jnl_create_info		create;
 	char			prev_jnl_fn[JNL_NAME_SIZE];
 	int			status;
+#	if defined(GTM_TRIGGER) && defined(DEBUG)
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
+#	endif
 	csa = &FILE_INFO(reg)->s_addrs;
 	jpc = csa->jnl;
-
-	assert((ERR_JNLFILOPN != sts) && (NOJNL != jpc->channel) || (ERR_JNLFILOPN == sts) && (NOJNL == jpc->channel));
+	assert(sts GTMTRIG_ONLY(|| TREF(in_trigger_upgrade)));
+	assert(!sts || ((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);
+	if (sts)
+		jnl_send_oper(jpc, sts);
 	/* attempt to create a new journal file */
 	memset(&create, 0, SIZEOF(create));
 	create.status = create.status2 = SS_NORMAL;
diff --git a/sr_port/jnl_write.c b/sr_port/jnl_write.c
index a35515d..673b1d2 100644
--- a/sr_port/jnl_write.c
+++ b/sr_port/jnl_write.c
@@ -50,6 +50,7 @@ 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;
+GBLREF	boolean_t		is_replicator;
 
 #ifdef DEBUG
 STATICDEF	int		jnl_write_recursion_depth;
@@ -520,7 +521,7 @@ void	jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor
 	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 (REPL_ENABLED(csa) && is_replicated && is_replicator)
 	{	/* 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.
diff --git a/sr_port/jnl_write_poolonly.c b/sr_port/jnl_write_poolonly.c
index 9a398f0..ee6601b 100644
--- a/sr_port/jnl_write_poolonly.c
+++ b/sr_port/jnl_write_poolonly.c
@@ -43,6 +43,7 @@ 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_replicator;
 
 error_def(ERR_JNLWRTDEFER);
 error_def(ERR_JNLWRTNOWWRTR);
@@ -71,6 +72,8 @@ void	jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype,
 	DEBUG_ONLY(uint4	lcl_dskaddr;)
 	uchar_ptr_t		tmp_buff;
 
+	if (!is_replicator)
+		return;
 	assert(NULL != jnl_rec);
 	assert(rectype > JRT_BAD  &&  rectype < JRT_RECTYPES && JRT_ALIGN != rectype);
 	assert(jrt_is_replicated[rectype]);
diff --git a/sr_port/job_addr.c b/sr_port/job_addr.c
index 1faf9d6..4e2c1b4 100644
--- a/sr_port/job_addr.c
+++ b/sr_port/job_addr.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -10,15 +10,22 @@
  ****************************************************************/
 
 #include "mdef.h"
+
+#include "gtm_string.h"
+
 #include "cmd_qlf.h"
 #include <rtnhdr.h>
 #include "op.h"
 #include "job_addr.h"
 #include "zbreak.h"
 
+GBLREF mident_fixed     zlink_mname;
+
 error_def(ERR_JOBLABOFF);
+error_def(ERR_ZLINKFILE);
+error_def(ERR_ZLMODULE);
 
-boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr)
+boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr, boolean_t *need_rtnobj_shm_free)
 {
 	rhdtyp		*rt_hdr;
 	int4		*lp;
@@ -31,8 +38,14 @@ boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labad
 		rt.mvtype = MV_STR;
 		rt.str = *rtn;
 		op_zlink(&rt, NULL);
-		assertpro(NULL != (rt_hdr = find_rtn_hdr(rtn)));
-	}
+		rt_hdr = find_rtn_hdr(rtn);
+		if (NULL == rt_hdr)
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->len, rtn->addr,
+				      ERR_ZLMODULE, 2, STRLEN(&zlink_mname.c[0]), &zlink_mname);
+		*need_rtnobj_shm_free = ARLINK_ONLY(rt_hdr->shared_object) NON_ARLINK_ONLY(FALSE);
+		*hdr = (char *)rt_hdr;
+	} else
+		*need_rtnobj_shm_free = FALSE;
 	lp = NULL;
 	if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == offset))
 		/* Label offset with routine compiled with NOLINE_ENTRY should cause error. */
@@ -40,7 +53,7 @@ boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labad
 	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;)
+	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.
diff --git a/sr_port/job_addr.h b/sr_port/job_addr.h
index b07094f..06f8cc5 100644
--- a/sr_port/job_addr.h
+++ b/sr_port/job_addr.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -12,6 +12,6 @@
 #ifndef __JOB_ADDR_H_
 #define __JOB_ADDR_H_
 
-boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr);
+boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr, boolean_t *need_rtnobj_shm_free);
 
 #endif
diff --git a/sr_port/jobparams.h b/sr_port/jobparams.h
index b15b406..e4e8b16 100644
--- a/sr_port/jobparams.h
+++ b/sr_port/jobparams.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -26,6 +26,7 @@
 	JPDEF (jp_nodetached,		jpdt_nul),
 	JPDEF (jp_noswapping,		jpdt_nul),
 	JPDEF (jp_output,		jpdt_str),
+	JPDEF (jp_passcurlvn,		jpdt_nul),
 	JPDEF (jp_priority,		jpdt_num),
 	JPDEF (jp_process_name,		jpdt_str),
 	JPDEF (jp_schedule,		jpdt_str),
diff --git a/sr_port/jobparamstrs.h b/sr_port/jobparamstrs.h
index 43d9ba3..aff456d 100644
--- a/sr_port/jobparamstrs.h
+++ b/sr_port/jobparamstrs.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -25,6 +25,9 @@ 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),
+#ifdef UNIX
+JPSDEF ( 4,  "PASS",	jp_passcurlvn),		JPSDEF ( 10,  "PASSCURLVN",	jp_passcurlvn),
+#endif
 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),
diff --git a/sr_port/lke.hlp b/sr_port/lke.hlp
index c110308..bcc0f91 100644
--- a/sr_port/lke.hlp
+++ b/sr_port/lke.hlp
@@ -557,15 +557,16 @@
 
    Copyright 2014
 
-   Fidelity Information Services, Inc. All rights reserved.
+   Fidelity National Information Services, Inc. and/or its subsidiaries. All
+   rights reserved.
 
    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or any
    later version published by the Free Software Foundation; with no Invariant
    Sections, no Front-Cover Texts and no Back-Cover Texts.
 
-   GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
-   trademarks are the property of their respective owners.
+   GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+   Other trademarks are the property of their respective owners.
 
    This document contains a description of GT.M and the operating
    instructions pertaining to the various functions that comprise the system.
@@ -576,7 +577,7 @@
 
    **Note**
 
-   This help file is a concise representation of revision V6.2-000 of the
+   This help file is a concise representation of revision V6.2-001 of the
    UNIX Administration and Operations Guide. To obtain a copy of the current
    revision, go to www.fis-gtm.com and then click on the User Documentation
    tab.
diff --git a/sr_port/lvzwr_init.c b/sr_port/lvzwr_init.c
index 11e4012..cfffe56 100644
--- a/sr_port/lvzwr_init.c
+++ b/sr_port/lvzwr_init.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -33,7 +33,9 @@ GBLREF uint4		zwrtacindx;
 void lvzwr_init(enum zwr_init_types zwrpattyp, mval *val)
 {
 	lvzwrite_datablk	*prevzwrb;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	/* 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).
 	 */
@@ -68,5 +70,6 @@ void lvzwr_init(enum zwr_init_types zwrpattyp, mval *val)
 	if (!lvzwrite_block->sub)
 		lvzwrite_block->sub = (zwr_sub_lst *)malloc(SIZEOF(zwr_sub_lst) * MAX_LVSUBSCRIPTS);
 	lvzwrite_block->fixed = TRUE;
+	TREF(in_zwrite) = TRUE;
 	return;
 }
diff --git a/sr_port/lvzwr_var.c b/sr_port/lvzwr_var.c
index e5e7e60..0307272 100644
--- a/sr_port/lvzwr_var.c
+++ b/sr_port/lvzwr_var.c
@@ -34,6 +34,7 @@
 #include "gtm_string.h"
 #include "alias.h"
 #include "promodemo.h"	/* for "demote" prototype used in LV_NODE_GET_KEY */
+#include "jobsp.h"
 
 #define eb_less(u, v)    (numcmp(u, v) < 0)
 
@@ -120,6 +121,15 @@
 		lvzwr_var((lv_val *)NODE, n + 1);						\
 }
 
+#ifdef UNIX
+/* job command needs to send the local variables to the child */
+#define MIDCHILD_SEND_VAR			\
+{						\
+	if (TREF(midchild_send_locals))		\
+		ojmidchild_send_var();		\
+}
+#endif
+
 GBLREF lvzwrite_datablk	*lvzwrite_block;
 GBLREF int4		outofband;
 GBLREF zshow_out	*zwr_output;
@@ -178,11 +188,11 @@ void lvzwr_var(lv_val *lv, int4 n)
 		return;
 	if (outofband)
 	{
-		assert(TREF(in_zwrite));
-		TREF(in_zwrite) = FALSE;
+		assert(TREF(in_zwrite));	/* in_zwrite indicates we are properly set up for a zwrite and should be cleared */
+		TREF(in_zwrite) = FALSE;	/* 	here along with the below 2 because outofband_action may not return */
 		lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
 		outofband_action(FALSE);
-		TREF(in_zwrite) = TRUE;
+		TREF(in_zwrite) = TRUE;		/* in case we come back because the outofband_action turns out to be info */
 	}
 	lvzwrite_block->curr_subsc = n;
 	zwr_sub = (zwr_sub_lst *)lvzwrite_block->sub;
@@ -216,6 +226,7 @@ void lvzwr_var(lv_val *lv, int4 n)
 			if (zav->value_printed)
 			{
 				lvzwr_out(lv);
+				UNIX_ONLY(MIDCHILD_SEND_VAR);
 				lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0;
 				return;
 			} else
@@ -230,6 +241,7 @@ void lvzwr_var(lv_val *lv, int4 n)
 		|| ((0 != n) && !(lvzwrite_block->mask >> n))))
 	{	/* Print value for *this* node  */
 		lvzwr_out(lv);
+		UNIX_ONLY(MIDCHILD_SEND_VAR);
 	}
 	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
diff --git a/sr_port/m_do.c b/sr_port/m_do.c
index 57d17ac..8208956 100644
--- a/sr_port/m_do.c
+++ b/sr_port/m_do.c
@@ -70,7 +70,7 @@ int m_do(void)
 				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 USHBIN_ONLY(if (OC_LAB_EXT != calltrip->operand[1].oprval.tref->opcode))
+				else ARLINK_ONLY(if (OC_LAB_EXT != calltrip->operand[1].oprval.tref->opcode))
 				{
 					assert(OC_LABADDR == calltrip->operand[1].oprval.tref->opcode);
 					assert(TRIP_REF == calltrip->operand[1].oprval.tref->operand[1].oprclass);
diff --git a/sr_port/m_zstep.c b/sr_port/m_zstep.c
index 9515a53..1215c89 100644
--- a/sr_port/m_zstep.c
+++ b/sr_port/m_zstep.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -20,7 +20,7 @@
 #include "cmd.h"
 #include "namelook.h"
 
-GBLREF short int 	source_column;
+GBLREF int 	source_column;
 
 error_def(ERR_INVZSTEP);
 error_def(ERR_ZSTEPARG);
diff --git a/sr_port/m_zwrite.c b/sr_port/m_zwrite.c
index 387fc47..cf8def9 100644
--- a/sr_port/m_zwrite.c
+++ b/sr_port/m_zwrite.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -30,7 +30,7 @@
 #include "mvalconv.h"
 #include "namelook.h"
 
-GBLREF short int 	source_column;
+GBLREF int	 	source_column;
 GBLREF uint4 		pat_everything[];
 GBLREF mstr_len_t	sizeof_pat_everything;
 
diff --git a/sr_port/maketriple.c b/sr_port/maketriple.c
index 9d4378a..c30ac66 100644
--- a/sr_port/maketriple.c
+++ b/sr_port/maketriple.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2009 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -14,7 +14,8 @@
 #include "mdq.h"
 #include "mmemory.h"
 
-GBLREF short int source_line,source_column;
+GBLREF short int source_line;
+GBLREF int	 source_column;
 
 triple *maketriple(opctype op)
 {
diff --git a/sr_port/md5_digest2hex.c b/sr_port/md5_digest2hex.c
deleted file mode 100644
index 40c8939..0000000
--- a/sr_port/md5_digest2hex.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/****************************************************************
- *								*
- *	Copyright 2014 Fidelity Information Services, Inc	*
- *								*
- *	This source code contains the intellectual property	*
- *	of its copyright holder(s), and is made available	*
- *	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 "eintr_wrappers.h"
-#include "gtm_string.h"
-#include "io.h"
-#include "gtmio.h"
-
-#include "md5hash.h"
-#include "md5_digest2hex.h"
-
-/*
- * Construct printable 32-character MD5 checksum string from raw 128-bit digest array.
- */
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH])
-{
-	int 	i, tlen;
-	char	*bptr;
-
-	bptr = (char *)&hexstr[0];
-	/* TODO - improve efficiency to avoid syscall using i2hexl() */
-	for (i = 0; i < MD5_DIGEST_LENGTH; i++)
-	{
-		tlen = SPRINTF(bptr, "%02x", digest[i]);
-		assert(2 == tlen);
-		bptr += tlen;
-	}
-	assert('\0' == hexstr[MD5_HEXSTR_LENGTH - 1]);
-}
diff --git a/sr_port/mdef.h b/sr_port/mdef.h
index bb3946a..7526145 100644
--- a/sr_port/mdef.h
+++ b/sr_port/mdef.h
@@ -83,6 +83,10 @@ typedef unsigned int 	uint4;		/* 4-byte unsigned integer */
  */
 #define SHMDT(X)	shmdt((void *)(X))
 
+/* Because shmget and semget returns -1 to indicate error, -1 can never be a valid shmid or semid */
+#define INVALID_SEMID			-1
+#define INVALID_SHMID 			-1L
+
 /* constant needed for FIFO - OS390 redefines in mdefsp.h */
 #define FIFO_PERMISSION		010666 /* fifo with RW permissions for owner, group, other */
 
@@ -112,20 +116,31 @@ error_def(ERR_ASSERT);
 # define lvaddr "%08lx"
 #endif
 
+/* Need to set a flag to 0 or 1 depending on whether AUTORELINK_SUPPORTED is set or not. This is needed by gtmpcat so it can
+ * tell if autorelink is supported on the platform or not. While this could be done by always setting AUTORELINK_SUPPORTED
+ * which a value of 0 or 1, that's not how the code that uses it is structured so create this new variable with a value
+ * depending on whether AUTORELINK_SUPPORTED is defined or not.
+ */
+#ifdef AUTORELINK_SUPPORTED
+# define ARLINK_ENABLED 1
+#else
+# define ARLINK_ENABLED 0
+#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
+ * 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)
+#if defined(UNIX) && ! defined(STATIC_ANALYSIS)
 #	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. */
+/* 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		-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.) */
@@ -333,7 +348,7 @@ typedef struct
 #	define HAS_LITERAL_SECT
 #endif
 
-typedef long		ulimit_t;	/* NOT int4; the Unix ulimit function returns a value of type long */
+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 */
@@ -455,6 +470,8 @@ mval *underr_strict(mval *start, ...);
 #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_UINT(M)	(MV_FORCE_DEFINED(M), MV_FORCE_UINTD(M))
+#define MV_FORCE_UINTD(M)	(DBG_ASSERT(MV_DEFINED(M)) (M)->mvtype & MV_INT ? (M)->m[1]/MV_BIAS : mval2ui(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)) : \
@@ -583,14 +600,6 @@ mval *underr_strict(mval *start, ...);
 /* 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);
@@ -672,7 +681,7 @@ int4 timeout2msec(int4 timeout);
 /* 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);
+void m_usleep(int useconds);
 #ifdef UNIX
 #	define SHORT_SLEEP(x) {assert(1000 > (x)); m_usleep((x) * 1000);}
 #else
@@ -723,10 +732,11 @@ int m_usleep(int useconds);
 #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. */
+ * 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)
@@ -740,10 +750,17 @@ int m_usleep(int useconds);
 #		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.
-*/
+/* Autorelink related macros */
+#ifdef AUTORELINK_SUPPORTED
+#	define ARLINK_ONLY(X)		X
+#	define NON_ARLINK_ONLY(X)
+#else
+#	define ARLINK_ONLY(X)
+#	define NON_ARLINK_ONLY(X)	X
+#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)
@@ -774,6 +791,9 @@ int m_usleep(int useconds);
    typedef	int64_t			gtm_int64_t;
 #endif
 
+int ceil_log2_32bit(uint4 num);
+int ceil_log2_64bit(gtm_uint64_t num);
+
 typedef INTPTR_T	sm_off_t;
 
 /* HPPA latches (used by load_and_clear) must be 16 byte aligned.
@@ -1384,7 +1404,7 @@ qw_num	gtm_byteswap_64(qw_num num64);
 #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 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
@@ -1728,7 +1748,7 @@ typedef enum
 #	define	GTM_SNAPSHOT_ONLY(X)
 #endif
 
-/* Currently MUPIP REORG -TRUNCATE is only supported on Unix */
+/* Currently MUPIP REORG -TRUNCATE is only supported on UNIX */
 #ifdef UNIX
 #	define	GTM_TRUNCATE
 #	define	NON_GTM_TRUNCATE_ONLY(X)
@@ -1738,7 +1758,7 @@ typedef enum
 #	define	GTM_TRUNCATE_ONLY(X)
 #endif
 
-/* Currently triggers are supported only on Unix */
+/* 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
diff --git a/sr_port/merrors.msg b/sr_port/merrors.msg
index 2139dd1..0679bda 100644
--- a/sr_port/merrors.msg
+++ b/sr_port/merrors.msg
@@ -492,7 +492,7 @@ EXTRACTFILERR	<Error with extract file !AD>/error/fao=2!/ansi=0
 FREEZE		<Region: !AD is already frozen>/info/fao=2!/ansi=0
 NOSELECT	<None of the selected variables exist -- halting>/warning/fao=0!/ansi=0
 EXTRFAIL	<Extract failed for the global ^!AD. MUPIP INTEG should be run.>/error/fao=2!/ansi=0
-LDBINFMT	<Corrupt binary format header information>/error/fao=0!/ansi=0
+LDBINFMT	<Unrecognized header for load file>/error/fao=0!/ansi=0
 NOPREVLINK	<Journal file !AD has a null previous link>/error/fao=2!/ansi=0
 CCEDUMPON	<>/fatal/fao=0!/ansi=0
 CCEDMPQUALREQ	<A qualifier (DB,[NO]ON, or NOW) is required with the DUMP command>/error/fao=0!/ansi=0
@@ -575,7 +575,7 @@ RECCNT		<Last LOAD record number: !UL>/info/fao=1!/ansi=0
 TEXT		<!AD>/info/fao=2!/ansi=0
 ZWRSPONE	<Subscript patterns in ZWRITE are atomic; Invalid delimiter>/error/fao=0!/ansi=0
 FILEDEL		<File !AD successfully deleted>/info/fao=2!/ansi=0
-JNLBADLABEL	<Journal file !AD does not have a GT.M Journal File Label>/error/fao=2!/ansi=0
+JNLBADLABEL	<Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.>/error/fao=6!/ansi=0
 JNLREADEOF	<End of journal file encountered for !AD>/error/fao=2!/ansi=0
 JNLRECFMT	<Journal file record format error encountered>/error/fao=0!/ansi=0
 BLKTOODEEP	<Block level too deep>/error/fao=0!/ansi=0
@@ -773,7 +773,7 @@ MEMORYRECURSIVE	<Memory Subsystem called recursively>/fatal/fao=0!/ansi=0
 FREEZEID	<Cache !AD on !AD by freeze id 0x!XL with match 0x!XL from 0x!XJ>/info/fao=7!/ansi=0
 BLKWRITERR	<Unable to queue disk write for block 0x!XL.  Will keep trying.>/info/fao=1!/ansi=0
 STOPTIMEOUT	<Waited too long for stopped process to release.  Region: !AD.>/error/fao=2!/ansi=0
-TRIGMODINTP	<Triggers for a given global cannot be both used and modified or removed in the same transaction>/error/fao=0!/ansi=0
+UNUSEDMSG776	<TRIGMODINTP last used in V6.2-000>/error/fao=0!/ansi=0
 BCKUPBUFLUSH	<Unable to flush buffer for online backup>/error/fao=0!/ansi=0
 NOFORKCORE	<Unable to fork off process to create core.  Core creation postponed.>/warning/fao=0!/ansi=0
 JNLREAD		<Error reading from journal file !AD at offset [0x!XL]>/error/fao=3!/ansi=0
@@ -806,7 +806,7 @@ MUKILLIP	<Kill in progress indicator is set for file !AD - this !AD operation is
 JNLRDONLY	<Journal file !AD read only>/error/fao=2!/ansi=0
 ANCOMPTINC	<Deviceparameter !AD is not compatible with any other deviceparameters in the !AD command>/error/fao=4!/ansi=0
 ABNCOMPTINC	<Deviceparameter !AD and deviceparameter !AD are not compatible in the !AD command>/error/fao=6!/ansi=0
-RECLOAD		<Error loading record number: !UL!/>/error/fao=1!/ansi=0
+RECLOAD		<Error loading record number: !@UQ!/>/error/fao=1!/ansi=0
 SOCKNOTFND	<Socket !AD not found>/error/fao=2!/ansi=0
 CURRSOCKOFR	<Current socket of index !UL is out of range.  There are only !UL sockets.>/error/fao=2!/ansi=0
 SOCKETEXIST	<Socket !AD already exists>/error/fao=2!/ansi=79
@@ -895,7 +895,7 @@ SECONDAHEAD	<Secondary ahead of primary. !/ Secondary database possibly updated
 SCNDDBNOUPD	<Database Updates not allowed on the secondary>/error/fao=0!/ansi=0
 MUINFOUINT4	<!AD : !UL [0x!XL]>/info/fao=4!/ansi=0
 NLMISMATCHCALC	<Location of !AD expected at 0x!XL, but found at 0x!XL>/error/fao=4!/ansi=0
-UNUSEDMSG898	<GTMSECSHRLOGSWH last used in V5.5-000>/error/fao=0!/ansi=0
+RELINKCTLFULL	<Relinkctl file for directory !AD is full (maximum entries !UL)>/error/fao=3!/ansi=0
 UNUSEDMSG899	<GTMSECSHRDEFLOG last used in V5.5-000>/info/fao=0!/ansi=0
 DBBADNSUB	<!AD Bad numeric subscript>/error/fao=2!/ansi=0
 DBBADKYNM	<!AD Bad key name>/error/fao=2!/ansi=0
@@ -1364,13 +1364,13 @@ TCOMMITDISALLOW	<TROLLBACK required after an unhandled error in trigger context>
 SSATTACHSHM	<Error while attaching to shared memory identifier !UL>/error/fao=1!/ansi=0
 TRIGDEFNOSYNC	<Global ^!AD has triggers defined on the !AD instance but none on the !AD instance. Current journal sequence number is 0x!16 at XQ>/warning/fao=7!/ansi=0
 TRESTMAX	<TRESTART not allowed in a final TP retry more than once>/error/fao=0!/ansi=0
-UNUSEDMSG1367	<TPLOCKRESTMAX : Last used in V5.5-000>/error/fao=0!/ansi=0
+ZLINKBYPASS	<ZLINK of !AD bypassed - Identical routine already linked>/info/fao=2!/ansi=0
 GBLEXPECTED	<Global variable reference expected in this context>/error/fao=0!/ansi=0
 GVZTRIGFAIL	<ZTRIGGER of a global variable failed.  Failure code: !AD.>/error/fao=2!/ansi=0
 MUUSERLBK	<Abnormal shutdown of replication-enabled database !AD detected>/error/fao=2!/ansi=0
 SETINSETTRIGONLY	<ISV !AD can only be modified in a 'SET' type trigger>/error/fao=2!/ansi=0
 DZTRIGINTRIG	<$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD>/error/fao=2!/ansi=0
-SECNODZTRIGINTP	<Sequence number 0x!16 at 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>/error/fao=1!/ansi=0
+UNUSEDMSG1373	<SECNODZTRIGINTP : Last used in V6.2-000>/error/fao=0!/ansi=0
 BOOLSIDEFFECT	<Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in Boolean expression>/warning/fao=0!/ansi=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.>/warning/fao=4!/ansi=0
 WRITEWAITPID	<PID !UL waited !UL minute(s) for PID !UL to finish writing block 0x!XL in database file !AD>/error/fao=6!/ansi=0
@@ -1382,7 +1382,7 @@ GTMSECSHRCHDIRF	<gtmsecshr unable to chdir to its temporary directory (!AD)>/err
 JNLORDBFLU	<Error flushing database blocks to !AD. See related messages in the operator log>/error/fao=2!/ansi=0
 ZCCLNUPRTNMISNG	<External call: Cleanup routine name missing. Cannot continue>/error/fao=0!/ansi=0
 ZCINVALIDKEYWORD	<External call: Invalid keyword found. Cannot continue>/error/fao=0!/ansi=0
-REPLNOMULTILINETRG	<Sequence number 0x!16 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication>/error/fao=1!/ansi=0
+UNUSEDMSG1385	<REPLNOMULTILINETRG : Last used in V6.2-000>/error/fao=0!/ansi=0
 DBSHMNAMEDIFF	<Database file !AD points to shared memory (id = !UL) which points to a different database file !AZ>/error/fao=4!/ansi=0
 SHMREMOVED	<Removed Shared Memory id !UL corresponding to file !AD>/info/fao=3!/ansi=0
 DEVICEWRITEONLY	<Cannot read from a write-only device>/error/fao=0!/ansi=0
@@ -1402,7 +1402,7 @@ LOCKSPACEUSE	<Estimated free lock space: !UL% of !UL pages>/info/fao=2!/ansi=0
 JIUNHNDINT	<An error during $ZINTERRUPT processing was not handled: !AD>/error/fao=2!/ansi=0
 GTMASSERT2	<!AD - Assert failed !AD line !UL for expression (!AD)>/fatal/fao=7!/ansi=0
 ZTRIGNOTRW	<ZTRIGGER cannot operate on read-only region !AD>/error/fao=2!/ansi=0
-TRIGMODREGNOTRW	<Trigger(s) cannot be added/changed/deleted because region !AD is read-only>/error/fao=2!/ansi=0
+TRIGMODREGNOTRW	<Trigger(s) cannot be added/changed/deleted/upgraded because region !AD is read-only>/error/fao=2!/ansi=0
 INSNOTJOINED	<Replicating Instance !AD is not a member of the same Group as Instance !AD>/error/fao=4!/ansi=0
 INSROLECHANGE	<Supplementary Instance !AD and non-Supplementary Instance !AD belong to the same Group>/error/fao=4!/ansi=0
 INSUNKNOWN	<Supplementary Instance !AD has no instance definition for non-Supplementary Instance !AD>/error/fao=4!/ansi=0
@@ -1536,7 +1536,7 @@ GBLNOMAPTOREG	<Global !AD does not map to region !AD in current global directory
 ISSPANGBL	<Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory>/error/fao=2!/ansi=0
 TPNOSUPPORT	<Operation cannot be performed while inside of a TP transaction>/error/fao=0!/ansi=0
 GVSUBSERR	<Invalid subscripted global name specification in $VIEW() function>/error/fao=0!/ansi=0
-TRIGNOSPANGBL	<Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory>/error/fao=2!/ansi=0
+UNUSEDMSG1539	<TRIGNOSPANBL : Last used in V6.2-000>/error/fao=0!/ansi=0
 FILTERTIMEDOUT	<Replication server timed out attempting to read seqno !16 at XQ from external filter>/error/fao=1!/ansi=0
 TLSDLLNOOPEN	<Failed to load GT.M TLS/SSL library for secure communication>/error/fao=0!/ansi=0
 TLSINIT		<Failed to initialize GT.M TLS/SSL library for secure communication>/error/fao=0!/ansi=0
@@ -1573,6 +1573,21 @@ CRYPTBADWRTPOS	<Encrypted WRITE disallowed from a position different than where
 LABELNOTFND	<GOTO referenced a label that does not exist>/error/fao=0!/ansi=13
 RELINKCTLERR	<Error with relink control structure for $ZROUTINES directory !AD>/error/fao=2!/ansi=0
 INVLINKTMPDIR	<Value for $gtm_linktmpdir is either not found or not a directory: !AD>/error/fao=2!/ansi=0
+NOEDITOR	<Can't find an executable editor: !AD>/error/fao=2!/ansi=0
+UPDPROC		<Update Process error>/error/fao=0!/ansi=0
+HLPPROC		<Helper Process error>/error/fao=0!/ansi=0
+REPLNOHASHTREC	<Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue>/error/fao=3!/ansi=0
+REMOTEDBNOTRIG	<Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file>/error/fao=4!/ansi=0
+NEEDTRIGUPGRD	<Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first>/error/fao=2!/ansi=0
+REQRLNKCTLRNDWN	<Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown>/error/fao=2!/ansi=0
+RLNKCTLRNDWNSUC	<Relinkctl file for $ZROUTINES directory !AD successfully rundown>/info/fao=2!/ansi=0
+RLNKCTLRNDWNFL	<Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)>/error/fao=3!/ansi=0
+MPROFRUNDOWN	<Error during M-profiling rundown>/error/fao=0!/ansi=0
+ZPEEKNOJNLINFO	<$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled>/error/fao=2!/ansi=0
+TLSPARAM	<TLS parameter !AD !AD>/error/fao=4!/ansi=0
+RLNKRECLATCH	<Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD>/error/fao=3!/ansi=0
+RLNKSHMLATCH	<Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD>/error/fao=2!/ansi=0
+JOBLVN2LONG	<The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL>/error/fao=2!/ansi=0
 !
 ! If there are UNUSEDMSG* lines unused for more than one year and at least two non-patch releases, use them before adding new lines.
 !
diff --git a/sr_port/mtables.c b/sr_port/mtables.c
index 900769f..2e3de5c 100644
--- a/sr_port/mtables.c
+++ b/sr_port/mtables.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -197,7 +197,6 @@ LITDEF boolean_t mvs_save[] =
 LITDEF mval skiparg		= DEFINE_MVAL_COMMON(0, 0, 0, 0, 0, 0, 0, 0);
 
 static readonly unsigned char localpool[7] = {'1', '1', '1', '0', '1', '0', '0'};
-LITDEF mval literal_null	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT | MV_NUM_APPROX | MV_UTF_LEN, 0, 0, 0, 0, 0, 0);
 LITDEF mval literal_zero	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 1, (char *)&localpool[3], 0,   0);
 LITDEF mval literal_one 	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 1, (char *)&localpool[0], 0,   1 * MV_BIAS);
 LITDEF mval literal_ten 	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 2, (char *)&localpool[2], 0,  10 * MV_BIAS);
@@ -214,26 +213,22 @@ LITDEF mval literal_oneeleven	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0,
  * try to set the MV_NUM_APPROX bit and that could cause a SIG-11 since these mvals are in the read-only data segment.
  * --------------------------------------------------------------------------------------------------------------------------
  */
-
+LITDEF mval literal_null	= DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT | MV_NUM_APPROX | MV_UTF_LEN, 0, 0, 0, 0, 0, 0);
 /* Create mval to hold batch type TSTART. "BA" or "BATCH" mean the same.
  * We define the shorter version here to try reduce the time taken for comparison.
  */
 LITDEF mval literal_batch       = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, TP_BATCH_SHRT, (char *)TP_BATCH_ID, 0, 0);
 
 #ifdef GTM_TRIGGER
-LITDEF mval literal_hasht	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, HASHT_GBLNAME_LEN    , (char *)HASHT_GBLNAME    , 0, 0);	/* BYPASSOK */
 LITDEF mval literal_hashlabel	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHLABEL_LEN, (char *)LITERAL_HASHLABEL, 0, 0);	/* BYPASSOK */
 LITDEF mval literal_hashcycle	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHCYCLE_LEN, (char *)LITERAL_HASHCYCLE, 0, 0);	/* BYPASSOK */
 LITDEF mval literal_hashcount	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_HASHCOUNT_LEN, (char *)LITERAL_HASHCOUNT, 0, 0);	/* BYPASSOK */
-LITDEF mval literal_cmd		= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_CMD_LEN      , (char *)LITERAL_CMD      , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_gvsubs	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_GVSUBS_LEN   , (char *)LITERAL_GVSUBS   , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_options	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_OPTIONS_LEN  , (char *)LITERAL_OPTIONS  , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_delim	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_DELIM_LEN    , (char *)LITERAL_DELIM    , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_zdelim	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_ZDELIM_LEN   , (char *)LITERAL_ZDELIM   , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_pieces	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_PIECES_LEN   , (char *)LITERAL_PIECES   , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_trigname	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_TRIGNAME_LEN , (char *)LITERAL_TRIGNAME , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_xecute	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_XECUTE_LEN   , (char *)LITERAL_XECUTE   , 0, 0);	/* BYPASSOK */
-LITDEF mval literal_chset	= DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, LITERAL_CHSET_LEN    , (char *)LITERAL_CHSET    , 0, 0);	/* BYPASSOK */
+
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	\
+	LITDEF mval LITMVALNAME = DEFINE_MVAL_LITERAL(MV_STR | MV_NUM_APPROX, 0, 0, STR_LIT_LEN(SUBSNAME), (char *)SUBSNAME, 0, 0);
+
+#include "trigger_subs_def.h"		/* BYPASSOK */
+#undef TRIGGER_SUBSDEF
 
 LITDEF mval gvtr_cmd_mval[GVTR_CMDTYPES] = {
 /* Define GVTR_CMD_SET, GVTR_CMD_KILL etc. */
@@ -251,10 +246,10 @@ LITDEF	int4	gvtr_cmd_mask[GVTR_CMDTYPES] = {
 };
 
 /* The initialization order of this array matches enum trig_subs_t defined in triggers.h */
-#define TRIGGER_SUBDEF(SUBNAME) LITERAL_##SUBNAME
 LITDEF char *trigger_subs[] = {
-#include "trigger_subs_def.h"
-#undef TRIGGER_SUBDEF
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	SUBSNAME,
+#include "trigger_subs_def.h"		/* BYPASSOK */
+#undef TRIGGER_SUBSDEF
 };
 
 #endif
diff --git a/sr_port/mu_extr_ident.c b/sr_port/mu_extr_ident.c
index e89928b..b9455fc 100644
--- a/sr_port/mu_extr_ident.c
+++ b/sr_port/mu_extr_ident.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -20,8 +20,16 @@
 #include "gtm_facility.h"
 #include "fileinfo.h"
 #include "gdsbt.h"
-#include "gdsfhead.h"	/* above includes needed for muextr.h */
-#include "muextr.h"	/* needed for "mu_extr_ident" prototype */
+#include "gdsfhead.h"		/* above includes needed for muextr.h */
+#include "muextr.h"		/* needed for "mu_extr_ident" prototype */
+
+#ifdef EXTRACT_HASHT_GLOBAL
+#include "gv_trigger_common.h"	/* for IS_GVKEY_HASHT_GBLNAME macro */
+/* $gtm_dist/mupip extract -select="^#t" is implemented as an internal debugging feature and only supports
+ * dumping ^#t. Using it with other globals won't work unless the ^#t is the last selected global because the
+ * macro IS_GVKEY_HASHT_GBLNAME checks (KEY_DELIMITER == ADDR[HASHT_GBLNAME_LEN]) which is true only when ^#t is
+ * the last parameter */
+#endif
 
 #define IDENT_FCHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || (x) == '%')
 #define IDENT_TAIL(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z') || ((x) >= '0' && (x) <= '9'))
@@ -32,6 +40,10 @@ char *mu_extr_ident(mstr *a)
 
 	b = a->addr;
 	c = b + a->len;
+#	ifdef EXTRACT_HASHT_GLOBAL
+	if (IS_GVKEY_HASHT_GBLNAME(a->len, b))
+		return (b + a->len);
+#	endif
 	if (IDENT_FCHAR(*b))
 		while (++b < c)
 			if (!IDENT_TAIL(*b))
diff --git a/sr_port/muextr.h b/sr_port/muextr.h
index a6efe99..5aed941 100644
--- a/sr_port/muextr.h
+++ b/sr_port/muextr.h
@@ -24,17 +24,14 @@ typedef	struct glist_struct
 #define	DO_ROOT_SEARCH_FALSE	FALSE
 #define	DO_ROOT_SEARCH_TRUE	TRUE
 
-#define	RECORDSTAT_REGION_LIT		" (region "
-#define	RECORDSTAT_REGION_LITLEN	STR_LIT_LEN(RECORDSTAT_REGION_LIT)
-
 #define	PRINT_REG_FALSE		FALSE
 #define	PRINT_REG_TRUE		TRUE
 
 #define	ISSUE_RECORDSTAT_MSG(GL_PTR, GBLSTAT, PRINT_REG)						\
 {													\
-	char	gbl_name_buff[MAX_MIDENT_LEN + 2 + RECORDSTAT_REGION_LITLEN + MAX_RN_LEN + 1];		\
+	char	gbl_name_buff[MAX_MIDENT_LEN + 2 + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1];		\
 					/* 2 for null and '^', MAX_RN_LEN for region name,		\
-					 * RECORDSTAT_REGION_LITLEN for " (region " and 1 for ")" */	\
+					 * SPANREG_REGION_LITLEN for " (region " and 1 for ")" */	\
 	int	gbl_buff_index;										\
 													\
 	gbl_name_buff[0]='^';										\
@@ -42,8 +39,8 @@ typedef	struct glist_struct
 	gbl_buff_index = 1 + GNAME(GL_PTR).len;								\
 	if (PRINT_REG && (NULL != GL_PTR->gvnh_reg->gvspan))						\
 	{												\
-		MEMCPY_LIT(&gbl_name_buff[gbl_buff_index], RECORDSTAT_REGION_LIT);			\
-		gbl_buff_index += RECORDSTAT_REGION_LITLEN;						\
+		MEMCPY_LIT(&gbl_name_buff[gbl_buff_index], SPANREG_REGION_LIT);				\
+		gbl_buff_index += SPANREG_REGION_LITLEN;						\
 		memcpy(&gbl_name_buff[gbl_buff_index], gl_ptr->reg->rname, gl_ptr->reg->rname_len);	\
 		gbl_buff_index += gl_ptr->reg->rname_len;						\
 		gbl_name_buff[gbl_buff_index++] = ')';							\
@@ -99,6 +96,7 @@ typedef struct coll_hdr_struct
 	unsigned char	pad;
 } coll_hdr;
 
+#define MU_FMT_UNRECOG		-1
 #define MU_FMT_GO		0
 #define MU_FMT_BINARY		1
 #define MU_FMT_GOQ		2
diff --git a/sr_port/mumps.hlp b/sr_port/mumps.hlp
index 23aa203..be6319d 100644
--- a/sr_port/mumps.hlp
+++ b/sr_port/mumps.hlp
@@ -390,7 +390,6 @@
    GTM>kill A,B
 
    GTM>set A=1,*B=A ; B & A are aliases
-
    GTM>write B
    1
    GTM>
@@ -490,7 +489,6 @@
    A=1 ;*
    *B=A
    GTM>Kill *A ; Remove the association for A - it now has no association and no array
-
    GTM>ZWRite ; B is a traditional local variable
    B=1
    Example:
@@ -510,12 +508,9 @@
    A=2 ;*
    *B=A
    GTM>Kill A ; Kill the array
-
    GTM>ZWRite ; There's no data to show - only the association
    *B=A
-
    GTM>Set B=3 ; Create a new value
-
    GTM>ZWRite ; The association was unaffected by the Kill
    A=3 ;*
    *B=A
@@ -571,13 +566,9 @@
    GTM>ZWRite ; Verify that it's there
    A=1 ;*
    *B=A
-
    GTM>Kill (A) ; Kill everything except A
-
    GTM>ZWRite ; Demonstrate that A also has no array
-
    GTM>Set A=2 ; Create an array
-
    GTM>ZWRite ; The association survived the Kill
    A=2 ;*
    *B=A
@@ -615,7 +606,6 @@
      zwrite
      tcommit ; No global updates in this transaction!
      quit
-
    ------------
    Initial values & association
    A="Malvern"
@@ -677,7 +667,6 @@
      write "Rollback doesnt restore names and local arrays",!
      zwrite
      quit
-
    ------------
    Only containers before transaction:
    $ZWRTAC=""
@@ -808,10 +797,10 @@
 
    In UTF-8 mode, string processing functions (such as $EXTRACT()) operate on
    strings of multi-byte characters, and can therefore produce different
-   results in M and UTF-8 modes, depending on the actual data processed,
-    Each function has a "Z" alter ego (for example, $ZEXTRACT()) that can be
-   used to operate on  sequences of bytes identically in M and UTF-8 modes
-   (that is, in M mode, $EXTRACT() and $ZEXTRACT() behave identically).
+   results in M and UTF-8 modes, depending on the actual data processed. Each
+   function has a "Z" alter ego (for example, $ZEXTRACT()) that can be used
+   to operate on sequences of bytes identically in M and UTF-8 modes (that
+   is, in M mode, $EXTRACT() and $ZEXTRACT() behave identically).
 
    In M mode, the concept of an illegal character does not exist. In UTF-8
    mode, a sequence of bytes may not represent a valid character, and
@@ -1601,6 +1590,20 @@
 
    By default, the compiler produces object modules.
 
+4 [no]w[arning]
+   [no]w[arning]
+
+   Instructs the compiler to suppress error output; the default is -warning.
+
+   When used with the -list qualifier, the -nowarning qualifier does not
+   affect errors in the listing.
+
+   **Note**
+
+   When used with the -noobject qualifier, the -nowarning qualifier instructs
+   the compiler to produce no object with no indication of the fact or the
+   cause.
+
 4 r[un]
    r[un]
 
@@ -1851,18 +1854,13 @@
    GTM>write $zgbldir
    /usr/lib/fis-gtm/V5.4-002B_x86/mumps.gld
    GTM>set $zgbldir="test.gld"
-
    GTM>set a=10
-
    GTM>set b=a
-
    GTM>recall
-
    1 set b=a
    2 set a=10
    3 set $zgbldir="test.gld"
    4 write $zgbldir
-
    GTM>
 
    This REC[ALL] command displays the previously entered commands.
@@ -3612,19 +3610,15 @@
    Wrong again
    %GTM-I-BREAK, Break instruction encountered
                At M source location break+2^br
-
    GTM>ZCONTINUE
    Iteration 3    x=1
    OK
    %GTM-I-BREAK, Break instruction encountered
                At M source location break+2^br
-
    GTM>ZCONTINUE
    %GTM-I-BREAK, Break instruction encountered
                At M source location break+2^br
-
    GTM>ZCONTINUE
-
    GTM>
 
    This uses a BREAK with both command and argument postconditionals. The
@@ -3690,10 +3684,8 @@
      if $view("undef") set revert=1 view "noundef"
      if z="" write "Missing parameter.",!     view:revert "undef" quit
      else  write z*z,! view:revert "undef" quit
-
    GTM>do ^SQR(10)
    100
-
    GTM>do ^SQR
    Missing parameter.
 
@@ -3942,9 +3934,7 @@
    Example:
 
    GTM>Set X=1,Y=1,Z=2 Kill UNDEF
-
    GTM>If X=1,Y=1,Z=3,UNDEF=0 Write "HI"
-
    GTM>
 
    The IF command causes GT.M to cease executing the line after it determines
@@ -4070,6 +4060,24 @@
    using a file extension of .mjo and the current default directory of the
    process created by the JOB command.
 
+4 PASSCURLVN
+   PASSCURLVN
+
+   When a JOB command specifies the PASSCURLVN jobparameter, the new process
+   inherits the current collation, all locals, aliases, and alias containers
+   from the JOB'ng process' current stack level. As a result of this, a
+   ZWRITE issued in the JOB'd process has the same output, except for any out
+   of scope aliases, as a ZWRITE in the context of the JOB command. If the
+   JOB command finds a ZWRITE representation of any lvn, consisting of a its
+   full name, its subscripts, corresponding value, quotes and the "=" sign,
+   exceeding 1MiB, it produces an JOBLVN2LONG error both in the JOB'ng
+   process and in the JOB'd processes error output stream. If a JOB command
+   does not specify PASSCURLVN, the JOB'd process(es) inherits no local
+   variables from the parent. While not an inexpensive command, you can use
+   the "exclusive" NEW command to control the context passed to the JOB'd
+   process; for example, adding "NEW (LOCALA, LOCALB)" before the JOB command
+   would pass only LOCALA and LOCALB.
+
 4 STA[RTUP]="/path/to/shell/script"
    STA[RTUP]="/path/to/shell/script"
 
@@ -4140,13 +4148,10 @@
    Example:
 
        kill *
-
        write !,"gtm_stdxkill=",+$ztrnlnm("gtm_stdxkill"),!
-
        set (A,B,C,E)="input"
        do X(.A,.B)
        zwrite
-
        write !,"____________",!
        set (A,B,C,E)="input"
        do Y(.A,.B)
@@ -4170,12 +4175,10 @@
    A="output"
    B="output"
    C="input"
-
    ____________
    A="output"
    B="output"
    C="input"
-
    ____________
    A="base" ;*
    B="base" ;*
@@ -4222,19 +4225,12 @@
    GTM>Set ^gbl1="one"
 
    GTM>Set ^gbl1(1,1)="oneone"
-
    GTM>Set ^gbl1(1,1,3)="oneonethree"
-
    GTM>Set ^gbl1(1,2,4)="onetwofour"
-
    GTM>Set ^gbl2(2)="gbl2_2"
-
    GTM>Set ^gbl2(2,1,3)="gbl2_2_1_3"
-
    GTM>Set ^gbl2(2,1,4,5)="gbl2_2_1_4_5"
-
    GTM>Merge ^gbl1(1)=^gbl2(2)
-
    GTM>WRITE $Reference
    ^gbl1(1)
    GTM>ZWRite ^gbl1
@@ -4269,11 +4265,8 @@
    GTM>Kill
 
    GTM>Set ^gbl(1,2)="1,2"
-
    GTM>Merge lcl(3,4)=^gbl(1)
-
    GTM>Set ^("naked")=2
-
    GTM>ZWRite ^gbl
    ^gbl(1,2)="1,2"
    ^gbl("naked")=2
@@ -4577,11 +4570,9 @@
    GTM>Set x="I love hotdogs"
 
    GTM>Set $Extract(x,3,6)="want"
-
    GTM>Write x
    I want hotdogs
    GTM>Set $Extract(x,7)=" many "
-
    GTM>Write x
    I want many hotdogs
    GTM>
@@ -4595,14 +4586,11 @@
    GTM>kill A,B
 
    GTM>set A=1,A(1)=1,A(2)=2
-
    GTM>set *B=A ; A & B are aliases.
-
    GTM>zwrite B
    B=1 ;*
    B(1)=1
    B(2)=2
-
    GTM>
 
    This SET * command creates an alias associated between A and B. It
@@ -4614,13 +4602,10 @@
    GTM>kill A,B,C
 
    GTM>set A=1,*C(2)=A ; C(2) is a container
-
    GTM>zwrite
    A=1 ;*
    *C(2)=A
-
    GTM>set *B=C(2) ; B is now an alias
-
    GTM>write B,":",$length(C(2)),":" ; An alias variable provides access but a container doesn't
    1:0:
    GTM>
@@ -4923,6 +4908,17 @@
    performance and exists primarily as a tool for use by FIS. The default is
    GDSCERT:0.
 
+4 GVSRESET
+   GVSRESET
+
+   Resets the process-specific fields that are part of the ZSHOW "G" result
+   and database file header fields holding records reported by: GVSTAT, BG
+   trace, buffer pool accounting and the TP block modification details. Note
+   a VIEW "GVSRESET" performed by a process with read-only database access
+   changes only the process-specific information and has no effect on the
+   database file header. DSE CHANGE -FILEHEADER -GVSTATSRESET clears the same
+   database file header fields as VIEW "GVRESET";
+
 4 GVDUPSETNOOP
    GVDUPSETNOOP
 
@@ -5103,6 +5099,31 @@
    the "?" operator. These pattern definitions can be used in place of, or in
    addition to, the standard C, N, U, L, and P.
 
+4 POOLLIMIT
+   POOLLIMIT
+
+   VIEW "POOLLIMIT":<region>:expr, where expr is of the form n[%] provides a
+   mechanism for a process that has the potential to "churn" global buffers
+   to limit the potential impact on other processes by restricting the number
+   of global buffers it uses. If the expression ends with a per-cent sign
+   (%), the number is taken as an as a percentage of the configured global
+   buffers and otherwise as an ordinal number of preferred buffers; standard
+   M parsing and integer conversions apply. Preferred buffer values are
+   limited to between 32 and one less than half the buffer pool inclusive;
+   with the exception of zero (0) or 100 per cent, which turn off the
+   limitation; specifications exceeding those limits provide the value of the
+   nearer limit. If the argument specifies "*" for the region, the command
+   applies to all regions. $VIEW("POOLLIMIT",<region>) returns the current
+   value for the region as an ordinal number - zero (0) when there is no
+   limit in place. Note that this facility is designed for use by a
+   relatively small subset of processes. In addition, MUPIP REORG uses this
+   facility to limit its buffers to a value established by the UNIX
+   environment variable (or OpenVMS logical name) gtm_poollimit using the
+   syntax described for VIEW "POOLLIMIT" with a default of 64 if
+   gtm_poollimit is not specified. Note that this may slightly slow a
+   standalone REORG but can be overridden by defining gtm_poollimit as 0 or
+   "100%".
+
 4 RCTLDUMP
    RCTLDUMP
 
@@ -5370,7 +5391,6 @@
    Line #4:   for i=1:1:$order(merval(""),-1)  do
    Line #5:   . kill:i#2 merval(i)
    Line #6:   quit
-
    GTM>
 
    This shows that merge^profiling has an elapsed time of 16231 and the
@@ -5414,7 +5434,6 @@
    execute the following commands:
 
    GTM>ZBREAK merge^profiling:"view ""TRACE"":1:""^mtrc"" write ""Trace"""
-
    GTM>do ^profiling
    Trace
    GTM>view "TRACE":0:"^mtrc"
@@ -5522,45 +5541,29 @@
        new i,j,k,v
        set k=1
        view "TRACE":1:"^trc"
-
        for i=1:1:3  set v=i
-
        for i=1:1  set v=0  quit:i=3
-
        for i=1,2:1:4,6  set v=0
-
        for i=1:1,2  set v=0  quit:i=3
-
        for i=1:1:2  for j=1:1:3  set v=0
-
        for i=1:1:2
        .    for j=1:1:1  do
        ..        set v=0
-
        set j=5  for i=1:1:j  do
        .    set j=(j-1)
-
        for i=1:1:2  for j=1:1:3  do
        .    set v=0
-
        for i=1:1:2  do
        .    for j=1:1:3  set v=0
-
        for i=1:1:2  do
        .    for j=1:1:3  do
        ..        set v=0
-
        for i="foo","bar",1:1  set v=0  quit:i=3
-
        for  set k=k+1  quit:k=3
-
        for i=1:1:3  for j=1:1:(3-i)  set v=0
-
        for i=1:1:3  for j=1:1:(3-i)  for k=1:1:(j+1)  set v=0
-
        set k=3  view "TRACE":0:"^trc"
        zwrite ^trc
-
        quit
 
    On executing fortypes, the output looks something like the following:
@@ -5628,7 +5631,6 @@
    GTM>Kill A
 
    GTM>View "NOUNDEF"
-
    GTM>Write A,?10,$L(A)
             0
    GTM>
@@ -5650,9 +5652,7 @@
    LAB  Write !,"THIS IS NOSENSE"
            Quit
    GTM>View "LABELS":"UPPER"
-
    GTM>ZLink "NOSENSE.m"
-
    GTM>Do ^NOSENSE
    THIS IS NOSENSE
    GTM>
@@ -5827,7 +5827,6 @@
    SUB  Write !,"This is ZBTEST"
         Quit
    GTM>ZBREAK SUB^ZBTEST
-
    GTM>Do ^ZBTEST
    %GTM-I-BREAKZBA, Break instruction encountered during ZBREAK action
    At M source location SUB^ZBTEST
@@ -5843,9 +5842,7 @@
    GTM>ZBREAK -*
 
    GTM>ZGOTO
-
    GTM>ZBREAK SUB^ZBTEST:"W !,""Trace"""
-
    GTM>Do ^ZBTEST
    Trace
    This is ZBTEST
@@ -6006,7 +6003,6 @@
    Example:
 
    GTM>ZGOTO
-
    GTM>ZSHow
    +1^GTM$DMOD (Direct mode)
    GTM>
@@ -6152,14 +6148,10 @@
 
    GTM>zlink "sockexamplemulti2"
    %GTM-E-LOADRUNNING, Cannot ZLINK an active routine sockexamplemulti2
-
    GTM>zshow "S"
    sockexamplemulti2+12^sockexamplemulti2    (Direct mode)
-
    GTM>view "LINK":"RECURSIVE"
-
    GTM>zlink "sockexamplemulti2"
-
    GTM>
 
    This example demonstrates how VIEW "LINK":"RECURSIVE" command ZLINKs a
@@ -6194,30 +6186,19 @@
 3 Auto-ZLINK_setup
    Auto-ZLINK setup
 
-   This section describes the procedure to setup the field test grade
-   auto-relink functionality that is available in V6.2-000. Although V6.2-000
-   when used without auto-relink (i.e., without use of the ZRUPDATE command
-   or the special syntax in $ZROUTINES) is a generally available, production
-   grade release, use auto-relink only in development and test environments
-   where field test grade functionality is acceptable.
-
-   By suffixing one or more directory names in $ZROUTINES with a single
-   asterisk (*), processes can subscribe to updates of object files published
-   in those directories. At the invocation of DO, GOTO, or ZGOTO, extrinsic
-   functions, $TEXT(), or ZPRINT that specify an entryref which includes a
-   routine name (vs. a label without a routine name), mumps processes (and
-   mupip processes executing trigger logic) automatically relink
-   ("auto-relink") and execute published new versions of routines.
-
-     o Label references (that is , without a routine name), whether direct or
-       through indirection, always refer to the current routine, and do not
-       invoke auto-relink logic.
-     o Use shell quoting rules when appending asterisks to directory names in
-       the gtmroutines environment variable - asterisks must be passed in to
-       GT.M, and not expanded by the shell.
-     o GT.M accepts but ignores asterisk suffixes to directory names on
-       32-bit Linux on x86 platforms, where it does not provide
-       auto-relinking.
+   This section describes the procedure to setup the auto-relink
+   functionality. GT.M loads an object file linked from an object directory
+   (in $ZROUTINES) with a *-suffix (i.e. auto-relink-enabled) into a shared
+   memory segment (referred to henceforth as a Rtnobj shared memory segment).
+   At the invocation of DO, GOTO, or ZGOTO, extrinsic functions, ZBREAK,
+   ZPRINT or
+
+   $TEXT()
+
+   that specify an entryref which includes a routine name (in contrast to a
+   label without a routine name), mumps processes (and mupip processes
+   executing trigger logic) automatically relink ("auto-relink") and execute
+   published new versions of routines.
 
    The ZRUPDATE command publishes of new versions of routines to subscribers.
    To remove routines, delete the object files and publish the names of the
@@ -6226,59 +6207,64 @@
 
    If the path to a file is non-existent, the request is ignored except in
    the case where one desires a currently shared object file (one that was
-   accessed before it was deleted) to no longer be shared. In V6.2-000, if
-   the process executing the ZRUPDATE does not have read permission to any
-   directory in the path to a file, ZRUPDATE ignores the request; FIS expect
-   to correct this in the production release.
-
-   To effect auto-relink, GT.M creates small temporary files in the directory
-   referred to by $gtm_linktmpdir (defaulting to $gtm_tmp, which in turn
-   defaults to /tmp, if unspecified). The names of these files are of the
-   form gtm-relinkctl-<md5sum> where <md5sum> is a hash of the realpath() to
-   an auto-relink directory. In the field test software, the permissions are
-   determined by the umask of the process creating a file. In the production
-   software, FIS intends for the group and permissions to match those for
-   shared resources as described in the section Shared Resources
-   Authorization Permissions in Appendix E (GT.M Security Philosophy) of the
-   UNIX Administration and Operations Guide. FIS recommends that all
-   processes that share a directory whose contents are subject to ZRUPDATE
-   use the same value for $gtm_linktmpdir so that all processes see update
-   notifications - with different values of $gtm_linktmpdir, a ZRUPDATE by a
-   process with one value of $gtm_linktmpdir would not be observed by a
-   process with a different value of that environment variable.
-
-   When a process that has subscribed to updates to routines in a directory
-   links to a routine from that directory, it maps the object file to its
-   address space, sharing the object code with other processes that are so
-   subscribed, and without requiring the object code to be placed in a shared
-   library. Processes that have not subscribed to updates link using
-   process-private heap space as they have in prior versions.
-
-   AIX has known architectural limitations to scalability when large numbers
-   of processes (thousands to tens of thousands) auto-relink large numbers of
-   routines (again thousands to tens of thousands of routines). In the
-   typical case where the number of dynamically modified routines is much
-   smaller than the total number of routines in an enterprise scale
-   application, a scalable way for large applications to use auto-relinking
-   on AIX is to place all routines in shared libraries, and define $ZROUTINES
-   with an auto-relink enabled patch directory preceding the shared library.
-   Scalability on HP-UX and Solaris is not known: FIS is not aware of any
-   inherent scalability issues other than those imposed by available hardware
-   resources when the product of the number of processes and the number of
-   auto-relinked remains well below the number of file descriptors made
-   available by the OS.
-
-   Changing $ZROUTINES currently causes all routines linked from
-   auto-relink-enabled directories in the process to be re-linked. FIS
-   intends for this to generate an error in the production release.
-
-   VIEW "RCTLDUMP" displays the created relinkctl files and the routines
-   looked for in their related directories. An entry in these files does not
-   mean that a given routine was found there. It merely means it was looked
-   for there and shows a cycle number (which ZRUPDATE bumps) whose change
-   indicates a new published version of the given object file. As it is a
-   diagnostic tool for the new feature, FIS may remove or modify this VIEW
-   option in subsequent releases.
+   accessed before it was deleted) to no longer be shared.
+
+   For each auto-relink enabled directory which a GT.M process accesses while
+   searching through $ZROUTINES, GT.M creates a small control file
+   (Relinkctl) in the directory identified by $gtm_linktmpdir (defaulting to
+   $gtm_tmp, which in turn defaults to /tmp, if unspecified). The names of
+   these files are of the form gtm-relinkctl-<murmur> where <murmur> is a
+   hash of the realpath() to an auto-relink directory; for example:
+   /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002). With each Relinkctl
+   file, GT.M creates and associates a block of shared memory that contains
+   associated control structures. Among the structures is a cycle number
+   corresponding to each routine found in the routine directory; a change in
+   the cycle number informs a process that it may need to determine whether
+   there is a new version of a routine. Although GT.M only creates relinkctl
+   records for routines that actually exist on disk, it may increment cycle
+   numbers for existing relinkctl records even if they no longer exist on
+   disk.
+
+   GT.M creates both the Relinkctl file and shared memory with permissions
+   based on the logic described in the "IPC Permissions" column of the
+   "Shared Resource Authorization Permissions" section in the Administration
+   and Operations Guide, except that the object directory, rather than the
+   database file, provides the base permissions.
+
+   The MUPIP RCTLDUMP command reports information related to relinkctl files
+   and their associated shared memory segments.
+
+   The environment variable gtm_autorelink_keeprtn if set to 1, t[rue], or
+   y[es] causes exiting processes to leave auto-relinked object code in the
+   shared memory repositories, while if undefined, 0, f[alse] or n[o] causes
+   exiting processes to purge any routines currently use by no processes. All
+   values are case-independent. When gtm_autorelink_keeprtn is defined and
+   TRUE:
+
+   FIS recommends that a directory in the $zroutines of a process be either
+   auto-relink-enabled or auto-relink-disabled for the life of the process.
+   Changing the auto-relink mode of the directory within a process is likely
+   to result in counter-intuitive results.
+
+   As arguments, ZRUPDATE takes object file names, including wild-cards of
+   the form accepted by $ZSEARCH(). If ZRUPDATE fails to find at least one
+   file to match an argument with a wild card, it issues an INFO message
+   (seen only if $PRINCIPAL has CENABLE). When an explicit name without a
+   wild card is specified, but there is no file in the directory or a
+   corresponding entry in the Relinkctl, ZRUPDATE produces an error. ZRUPDATE
+   issues most errors as FILEPARSE errors with a secondary error describing
+   the actual issue although some errors, depending on the reason and path by
+   which ZRUPDATE detects them, can be rather cryptic.
+
+   An explicit ZLINK or an auto-relink check the hash of an object and its
+   replacement. If they are identical, GT.M takes no action to replace the
+   current object, saving both memory and time.
+
+   An explicit ZLINK from an auto-relink directory acts as an implicit
+   ZRUPDATE.
+
+   Any ZBREAK in a routine disables that routine from auto-relinking by a
+   process until all ZBREAKs are removed.
 
 3 ZLINK,_auto-ZLINK_and_Routine_Names
    ZLINK, auto-ZLINK and Routine Names
@@ -6330,7 +6316,6 @@
    Example:
 
    GTM>ZMessage 2
-
    %SYSTEM-E-ENO2, No such file or directory
 
    This ZMESSAGE does not specify substitution text and the message does not
@@ -6389,7 +6374,6 @@
    GTM>ZPRINT X^RTN:X+5
 
    GTM>ZPRINT X+-5^RTN:X
-
    GTM>ZPRINT X^RTN:X+-5^RTN
 
    The first line displays the line beginning with the label X and the next 5
@@ -6407,6 +6391,13 @@
 
    This command displays the trigger code for trigger name A#1#.
 
+   ZPRINT ^x#/BREG : Print trigger routine user-named "x" in region BREG
+   ZPRINT ^x#1#/BREG : Print trigger routine auto-named "x#1" in region BREG
+   ZPRINT ^x#1#A/BREG : Print trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+   ZPRINT +1^x#1#A/BREG : Print line 1 of trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+
+   These are some examples of disambiguator combinations.
+
 2 ZRUPDATE
    ZRUPDATE
 
@@ -6429,7 +6420,7 @@
        was accessed before it was deleted) to no longer be shared. In
        V6.2-000, if the process executing the ZRUPDATE does not have read
        permission to any directory in the path to a file, ZRUPDATE ignores
-       the request; FIS expects to correct this in the production release.
+       the request; FIS expect to correct this in the production release.
      o To effect auto-relink, GT.M creates small temporary files in the
        directory referred to by $gtm_linktmpdir (defaulting to $gtm_tmp,
        which in turn defaults to /tmp, if unspecified). The names of these
@@ -6462,6 +6453,14 @@
    A ZSHOW argument is an expression containing codes selecting one or more
    types of information.
 
+   A: A stands for Autorelink and provides output in the same format as MUPIP
+   RCTLDUMP, but restricted to the routines linked by the process issuing the
+   command. ZSHOW "*" does not include ZSHOW "A" because of an expectation
+   that the typical volume of the information does not provide a good return
+   for its value. If you wish your error handling or INTRPT routines to dump
+   this information, ask for it explicitly, possibly by doing a ZSHOW "A"
+   into a local variable before doing a ZSHOW "*".
+
    B: displays active ZBREAK breakpoints
 
    D: displays device information
@@ -6473,8 +6472,8 @@
 
    L: displays GT.M LOCKs and ZALLOCATEs held by the process
 
-   R: displays the GT.M invocation stack and an MD5 checksum of M source code
-   for each routine on the stack.
+   R: displays the GT.M invocation stack and a hash based on the MurmurHash3
+   algorithm of M source code for each routine on the stack.
 
    S: displays the GT.M invocation stack
 
@@ -6506,6 +6505,14 @@
    SET : # of SET operations (TP and non-TP)
    KIL : # of KILl operations (kill as well as zwithdraw, TP and non-TP)
    GET : # of GET operations (TP and non-TP)
+   CAT : total of critical section acquisitions successes
+   CFE : total attempts in CFT caused by epochs
+   CFS : sum of squares of blocked critical section acquisitions
+   CFT : total of blocked critical section acquisitions
+   CQS : sum of squares of critical section acquisition queued sleeps
+   CQT : total of critical section acquisition queued sleeps
+   CYS : sum of squares of critical section acquisition processor yields
+   CYT : total of critical section acquisition processor yields
    DTA : # of DaTA operations (TP and non-TP)
    ORD : # of $ORDer() operations (TP and non-TP). The count of $Order(xxx,1) operations are reported under this item.
    ZPR : # of $ZPRevious() (reverse order) operations (TP and non-TP). The count of $Order(xxx,-1) operations are reported under this item.
@@ -6552,7 +6559,6 @@
    JRO : # of all journal records other than logical, PBLK, AIMG and EPOCH records written to the journal file (for example, PINI, PFIN, and so on.)
    JEX : # of times a process extends the journal file
    DEX : # of times a process extends the database file
-
    [NT]B[WR] mnemonics are satisfied by either disk access or, for databases that use the BG (buffered global) access method, global buffers in shared memory.
 
 3 Examples
@@ -6603,12 +6609,10 @@
    GLD:*,REG:*,SET:205,KIL:0,GET:1,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:9,DWT:15,
    NTW:203,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,TBW:2,TBR:6,
    TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
    GLD:/home/gtmuser1/.fis-gtm/V5.4-002B_x86/g/mumps.gld,REG:DEFAULT,SET:205,KIL:0,GET:1,
    DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:411,DRD:9,DWT:15,NTW:2
    03,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,TBW:2,TBR:6,TR0:0,
    TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
    GLD:/tmp/tst/test.gld,REG:DEFAULT,SET:205,KIL:0,GET:1,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,
    CTN:411,DRD:9,DWT:15,NTW:203,NTR:4,NBW:212,NBR:414,NR0:0,NR1:0,NR2:0,NR3:0,TTW:1,TTR:0,TRB:0,
    TBW:2,TBR:6,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
@@ -6624,7 +6628,6 @@
    GLD:*,REG:*,SET:0,KIL:0,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:0,DWT:0,NTW:0,
    NTR:0,NBW:0,NBR:0,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,TTR:0,TRB:0,
    TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
-
    GLD:/tmp/x1.gld,REG:REG1,SET:0,KIL:0,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:0,
    DWT:0,NTW:0,NTR:0,NBW:0,NBR:0,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,
    TTR:0,TRB:0,TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0
@@ -6651,9 +6654,7 @@
    Example:
 
    GTM>LOCK ^FAIL:10
-
    GTM>lock (^SUCCESS1,^SUCCESS2)
-
    GTM>zshow "L"
    MLG:1,MLT:1
    LOCK ^SUCCESS1 LEVEL=1
@@ -6721,7 +6722,6 @@
 
    GTM>KILL  SET a(1,"D",3,5)="stuff",a(1,"X",2)="",a(1)=1
    GTM>ZSHow "d":a(1)
-
    GTM>ZWRite
    a(1)=1
    a(1,"D",1)="/dev/pts/1 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
@@ -6737,7 +6737,6 @@
    GTM>KILL ^ZSHOW
 
    GTM>ZB -*,lab^rout ZSH "B":^ZSHOW
-
    GTM>ZWRite ^ZSHOW
    ^ZSHOW("B",1)="LAB^ROUT"
    GTM>
@@ -7345,9 +7344,7 @@
        for i=1:1:$length(x) quit:" "'=$extract(x,i)
        for j=$length(x):-1:1 quit:" "'=$extract(x,j)
        quit $extract(x,i,j)
-
    GTM>set str=" MUMPS "
-
    GTM>write $length(str)
    7
    GTM>write $length($$^trim(str))
@@ -7395,7 +7392,6 @@
    Example:
 
    GTM>set t=1 for  set t=$find("BANANA","AN",t) quit:'t  write !,t
-
    4
    6
    GTM>
@@ -7798,9 +7794,7 @@
    Example:
 
    GTM>kill  set (a(1),a(2000),a("CAT"),a("cat"),a("ALF"),a(12))=1
-
    GTM>set x="" for  set x=$order(a(x)) quit:x=""  write !,x
-
    1
    12
    2000
@@ -7808,9 +7802,7 @@
    CAT
    cat
    GTM>kill a("CAT") set a(5,10)="woolworths",a("cat")="last"
-
    GTM>set x="" for  set x=$order(a(x),-1) quit:x=""  write !,x
-
    cat
    ALF
    2000
@@ -7832,7 +7824,6 @@
    GTM>kill set (%(1),tiva(2),A(3),tiv(4),Q(5),%a(6))=""
    GTM>set x="%"
    GTM>write:$data(@x) !,x for  set x=$order(@x) quit:x=""  write !,x
-
    %
    %a
    A
@@ -7842,7 +7833,6 @@
    x
    GTM>set $piece(x,"z",32)=""
    GTM>write:$data(@x) !,x for  set x=$order(@x,-1) quit:x=""  write !,x
-
    x
    tiva
    tiv
@@ -7944,7 +7934,6 @@
    GTM>write $data(^|"XXX"|ABC(1,2,3,4))
    0
    GTM>set X=$name(^(5,6))
-
    GTM>write $qlength(X)
    5
 
@@ -8044,7 +8033,6 @@
    lcl(1,2,"abc",5)=7
    lcl("x")=1
    GTM>set y="lcl"
-
    GTM>for  set y=$query(@y) quit:y=""  write !,y,"=", at y
 
    This example produces the results:
@@ -8144,12 +8132,10 @@
    Example:
 
    GTM>for i=3:-1:0 write !,$select(i=1:"here",i=2:"come",i=3:"Watson")
-
    Watson
    come
    here
    %GTM-E-SELECTFALSE, No argument to $SELECT was true
-
    GTM>
 
    This loop uses $SELECT() to WRITE a series of strings. Because there is no
@@ -8214,7 +8200,6 @@
    DLabel
      write !,$STACK
      quit
-
    0
    1
    1
@@ -8230,7 +8215,6 @@
     for l=dsm1:-1:0 do
     . write !,l
     . for i="ecode","place","mcode" write ?5,i,?15,$stack(l,i),!
-
    GTM>
 
    The above example can be used to display a trace of the code path that led
@@ -8245,53 +8229,40 @@
     if x>0 set $ecode=",U1," ; if condition
     else  set $ecode=",U2," ;  else condition
     quit
-
    GTM>do ^dstacktst(0)
-
    $stack(-1):2
    2    ecode
         place     debugerr+3^debugerr
         mcode      for l=dsm1:-1:0 do
-
    1    ecode     ,U2,
         place     label+2^dstacktst
         mcode      else  set $ecode=",U2," ;  else condition
-
    0    ecode
         place     +1^GTM$DMOD
         mcode
    %GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
    GTM>do ^dstacktst(1)
-
    $stack(-1):1
    1    ecode     ,U2,
         place     label+2^dstacktst
         mcode      else  set $ecode=",U2," ;  else condition
-
    0    ecode
         place     +1^GTM$DMOD
         mcode
    %GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
    GTM>set $ecode=""
-
    GTM>do ^dstacktst(1)
-
    $stack(-1):2
    2    ecode
         place     debugerr+3^debugerr
         mcode      for l=dsm1:-1:0 do
-
    1    ecode     ,U1,
         place     label+1^dstacktst
         mcode      if x>0 set $ecode=",U1," ; if condition
-
    0    ecode
         place     +1^GTM$DMOD
         mcode
    %GTM-E-SETECODE, Non-empty value assigned to $ECODE (user-defined error trap)
-
    GTM>
 
    This example shows how SETing $ECODE=.. makes $STACK() reports current
@@ -8458,13 +8429,11 @@
    |"GVNEXT"         |region        |Name of the next database region after the given one in alphabetical order (or M collation sequence); "" for region|
    |                 |              |starts with the first region. A return value of "" means that the global directory defines no additional regions.  |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
-   |                 |              |Encoded information about database behavior since segment creation. It also includes SET operations even if they   |
-   |                 |              |are inside a TP transaction.                                                                                       |
+   |                 |              |When                                                                                                               |
    |                 |              |                                                                                                                   |
-   |"GVSTAT"         |region        |If you require completely accurate GVSTATS, you need to ensure the last process to close a database always has     |
-   |                 |              |write access to the database files. If read-only processes are the active processes in a database, they cannot     |
-   |                 |              |update the database and may delete the shared memory where they have stored the counts of their actions (for       |
-   |                 |              |example, the number of blocks read).                                                                               |
+   |"GVSTAT"         |region        |read-only processes are the active in a database, they cannot update the database including the file header where  |
+   |                 |              |GVSTATS are stored. Therefore their counts are only stored in associated shared memory and must be flushed to the  |
+   |                 |              |file header by a process with write access, which might be a MUPIP RUNDOWN.                                        |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
    |                 |              |Number of indirection cache hits since GT.M process startup.                                                       |
    |"ICHITS"         |none          |                                                                                                                   |
@@ -8509,6 +8478,9 @@
    |                 |              |By default, GT.M ensures Isolation, that is, a $VIEW command will return 0. The isolation-status of a global       |
    |                 |              |variable can be turned on and off by the VIEW "NOISOLATION" command.                                               |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
+   |"PROBECRIT"      |region        |Acquires and releases a critical section for the region (the "probe"), returning a string with the following       |
+   |                 |              |fields:                                                                                                            |
+   |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
    |                 |              |Name of the region(s) holding the specified gvn.                                                                   |
    |                 |              |                                                                                                                   |
    |                 |              |If gvn spans more than one region, this function returns region name in an order where the first region is the     |
@@ -8521,7 +8493,8 @@
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
    |"PATCODE"        |none          |Name of the active patcode table; GT.M defaults this to "M".                                                       |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
-   |"RTNCHECKSUM"    |routine name  |Returns the source check-sum for the most recently ZLINK'd version of the specified routine name.                  |
+   |"RTNCHECKSUM"    |routine name  |Use a 128 bit hash based on the MurmurHash3 algorithm to returns the source check-sum for the most recently ZLINK'd|
+   |                 |              |version of the specified routine name.                                                                             |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
    |"RTNNEXT"        |routine name  |Name of the next routine in the image after the given one; "" (empty string) for routinename starts with the first |
    |                 |              |routine in ASCII collating sequence and a return value of the empty string indicates the end of the list.          |
@@ -8558,11 +8531,10 @@
    |                 |              |Displays the global name or a global name with subscript(s) of a database representation gds. The option collnum   |
    |                 |              |specifies the collnum specifies the alternate collation sequence number. If collnum is not specified, GT.M assumes |
    |                 |              |the default ASCII collation(collnum=0). This function is the inverse of the $VIEW("YGVN2GDS",<gvn>[,collnum])      |
-   |                 |              |function. For example:                                                                                             |
-   |"YGDS2GVN"       |gds[,collnum])|                                                                                                                   |
+   |"YGDS2GVN"       |gds[,collnum])|function. For example:                                                                                             |
+   |                 |              |                                                                                                                   |
    |                 |              |GTM>set y=$VIEW("YGDS2GVN",x) zwrite y                                                                             |
    |                 |              |y="^A(1,""abcd"")"                                                                                                 |
-   |                 |              |                                                                                                                   |
    |                 |              |GTM>                                                                                                               |
    |-----------------+--------------+-------------------------------------------------------------------------------------------------------------------|
    |"ZDATE_FORM"     |none          |Integer value showing whether four digit year code is active for $ZDATE(); GT.M defaults to 0 (for "YY" format).   |
@@ -8582,7 +8554,6 @@
    Example:
 
    GTM>Set a=1,*b(1)=a
-
    GTM>write $view("LV_CREF","a")," ",$view("LV_CREF","b")
    1 0
    GTM>write $view("LV_REF","a")," ",$view("LV_REF","b")
@@ -8596,9 +8567,7 @@
    Example:
 
    GTM>Set *a(1)=b,*b(1)=a
-
    GTM>kill *a,*b
-
    GTM>write $view("LV_GCOL")
    2
    GTM>
@@ -8666,15 +8635,12 @@
    Example:
 
    GTM>set A=1,*B(1)=A
-
    GTM>write "$zahandle(A)=""",$zahandle(A),""" $zahandle(B(1))=""",$zahandle(B(1)),""""
    $zahandle(A)="17B8810" $zahandle(B(1))="17B8810"
    GTM>set A("Subscript")="Value" ; Change array - but $ZAHandle() doesn't change
-
    GTM>write "$zahandle(A)=""",$zahandle(A),""" $zahandle(B(1))=""",$zahandle(B(1)),""""
    $zahandle(A)="17B8810" $zahandle(B(1))="17B8810"
    GTM>merge D=A ; A copy of the data has a different $zahandle()
-
    GTM>Write "$ZAHandle(A)=""",$ZAHandle(A),""" $ZAHandle(D)=""",$ZAHandle(D),""""
    $zahandle(A)="17B8810" $zahandle(D)="17B8C10"
    GTM>
@@ -8776,9 +8742,7 @@
    ; The binary representation of A is 01000001
    GTM>Set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
    ; The binary representation of B is 01000010
-
    GTM>set BITSTRINGAB=$zbitand(BITSTRINGA,BITSTRINGB)
-
    GTM>for i=1:1:8 write $zbitget(BITSTRINGAB,I)
    01000000
 
@@ -8804,13 +8768,10 @@
 
    GTM>set BITSTRINGA=$ZBITSET($ZBITSET($ZBITSTR(8,0),2,1),8,1)
    ; The binary representation of A is 01000001
-
    GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
    ; The binary representation of B is 01000010
-
    GTM>Set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB)
    ; A OR B=01000011
-
    GTM>write $zbitcount(BITSTRINGA)
    2
    GTM>write $zbitcount(BITSTRINGB)
@@ -8843,7 +8804,6 @@
 
    GTM>Set BITSTRINGA=$ZBITSET($ZBITSET($ZBITSTR(8,0),2,1),8,1)
    ; The binary representation of A is 01000001
-
    GTM>write $zbitfind(BITSTRINGA,1,3)
    9
    GTM>
@@ -8868,7 +8828,6 @@
 
    GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
    ; The binary representation of A is 01000001
-
    GTM>for i=1:1:8 write $zbitget(BITSTRINGA,I)
    01000001
    GTM>
@@ -8909,7 +8868,6 @@
 
    GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
    ; The binary representation of A is 01000001
-
    GTM>for i=1:1:8 write $zbitget($zbitnot(BITSTRINGA),I)
    10111110
    GTM>
@@ -8934,13 +8892,10 @@
 
    GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1)
    ; The binary representation of A is 01000001
-
    GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1)
    ; The binary representation of B is 01000010
-
    GTM>set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB)
    ; A OR B=01000011
-
    GTM>write BITSTRINGC
    C
    GTM>
@@ -9003,11 +8958,8 @@
    Examples
 
    GTM>set BITSTRINGA=$zbitset($zbitset($zbitstr(8,0),2,1),8,1) ; The binary representation of A is 01000001
-
    GTM>set BITSTRINGB=$zbitset($zbitset($zbitstr(8,0),2,1),7,1); The binary representation of B is 01000010
-
    GTM>set BITSTRINGC=$zbitor(BITSTRINGA,BITSTRINGB) ; A XOR B=00000011
-
    GTM>for I=1:1:8 write $zbitget(BITSTRINGC,I)
    00000011
    GTM>
@@ -9149,11 +9101,9 @@
    GTM>Write $Length(T8)
    12
    GTM>Set T16=$zconvert(T8,"UTF-8","UTF-16LE")
-
    GTM>Write $length(T16)
    %GTM-E-BADCHAR, $ZCHAR(129,137,232,150) is not a valid character in the UTF-8 encoding form
    GTM>Set T16=$ZCOnvert(T16,"UTF-16LE","UTF-8")
-
    GTM>Write $length(T16)
    9
 
@@ -9193,7 +9143,6 @@
    GTM>write $data(b(1))," ",$zdata(b(1))
    1 101
    GTM>set b(1,2)=2
-
    GTM>write $data(b(1))," ",$zdata(b(1))
    11 111
    GTM>write $data(b(1,2))," ",$zdata(b(1,2))
@@ -9348,7 +9297,6 @@
    Example:
 
    GTM>write !,$zdate($H,"12:60:SS AM")
-
    10:35:51 PM
    GTM>
 
@@ -9358,7 +9306,6 @@
    Example:
 
    GTM>write !,$zdate(",36524","24-60")
-
    10-08
    GTM>
 
@@ -9373,7 +9320,6 @@
    GTM>write $zdate($H)
    01/18/11
    GTM>set $zdateform=1
-
    GTM>write $zdate($horolog)
    01/18/2011
    GTM>write $zdate($horolog,"MM/DD/YY")
@@ -9408,9 +9354,7 @@
    GTM>Set A="************"
 
    GTM>For i=0:1:$zlength(A)
-
    GTM>write !,$zascii($zextract(A,i)),"|"
-
    GTM>
 
    This example displays the numeric byte sequence of the sequence of octets
@@ -9451,7 +9395,6 @@
    Example:
 
    GTM>set t=1 for  set t=$zfind("***",$zchar(230,150,176),t) quit:'t  write !,t
-
    4
    GTM>
 
@@ -9502,7 +9445,6 @@
    to $ZPARSE(), as illustrated by the following M code:
 
    set deffn="GTM_JOBEXAMINE.ZSHOW_DMP_"_$JOB_"_"_<cntr>
-
    set filespec=$zparse(expr1,"",deffn)
 
    The $ZJOBEXAM()does not trigger error processing except when there is a
@@ -9526,7 +9468,6 @@
    GTM>write x
    /home/gtmuser1/.fis-gtm/V5.4-002B_x86/r/GTM_JOBEXAM.ZSHOW_DMP_28760_1
    GTM>set x=$zjobexam("test.file")
-
    GTM>write x
    /home/gtmuser1/.fis-gtm/V5.4-002B_x86/r/test.file
    GTM>
@@ -9625,7 +9566,6 @@
    Example:
 
    GTM>write $zmessage(36)
-
    Interrupted system call
    GTM>
 
@@ -9768,7 +9708,6 @@
    Example:
 
    GTM>for i=0:1:3 write !,$zpiece("*"_$zchar(64)_"*",$zchar(64),i),"|"
-
    |
    *|
    *|
@@ -9782,13 +9721,11 @@
    Example:
 
    GTM>for i=-1:1:3 write !,$zpiece("*"_$zchar(64)_"*",$zchar(64),i,i+1),"|"
-
    |
    *|
    *@*|
    *|
    |
-
    GTM>
 
    This example is similar to the previous example except that it displays
@@ -9805,7 +9742,7 @@
    Example:
 
    GTM>Set $piece(x,$zchar(64),25)="" write x
-   ***@@@@@@@@@@@@@@@@@@@@@@@@
+   ???@@@@@@@@@@@@@@@@@@@@@@@@
 
    This SETs the 25th piece of the variable x to null, with delimiter
    $ZCHAR(64). This produces a byte sequence of 24 at-signs (@) preceding the
@@ -9829,100 +9766,116 @@
 
    $ZPEEK("mnemonic[:argument]",offset,length[,format])
 
-     o mnemonic specifies the memory area $ZPEEK() is to access. Some
+     * mnemonic specifies the memory area $ZPEEK() is to access. Some
        mnemonics have arguments separated from the mnemonic by a colon (":").
        The mnemonics are case independent. Possible mnemonics, their possible
        abbreviations and their arguments are:
 
-          o CSA[REG] - returns a value from the sgmnt_addrs (process private)
+          * CSA[REG] - returns a value from the sgmnt_addrs (process private)
             control block. Takes a case independent region name as an
             argument.
-          o FH[REG] - returns a value from the sgmnt_data (shared file
+          * FH[REG] - returns a value from the sgmnt_data (shared file
             header) control block. Takes a case independent region name as an
             argument.
-          o GDR[REG] - returns a value from the gd_region (process private)
+          * GDR[REG] - returns a value from the gd_region (process private)
             control block. Takes a case independent region name as an
             argument.
-          o GLF[REPL] - returns a value from the jnlpool.gtmsrc_lcl_array[n]
+          * GLF[REPL] - returns a value from the jnlpool.gtmsrc_lcl_array[n]
             control block. Takes a numeric index (n) as an argument.
-          o GRL[REPL] - returns a value from the recvpool.gtmrecv_local
+          * GRL[REPL] - returns a value from the recvpool.gtmrecv_local
             control block. No argument allowed. Only available when run on a
             non-primary instance.
-          o GSL[REPL] - returns a value from the
+          * GSL[REPL] - returns a value from the
             jnlpool.gtmsource_local_array[n] control block. Takes a numeric
             index (n) as an argument.
-          o JPC[REPL] - returns a value from the jnlpool.jnlpool_ctl control
+          * JBF[REG]:region[ -obtains fields in shared jnl_buffer structure.
+          * JNL[REG]:region[ - obtains fields in the jnl_private_control
+            structure.
+          * JPC[REPL] - returns a value from the jnlpool.jnlpool_ctl control
             block. No argument allowed.
-          o NL[REG] - returns a value from the node_local (shared) control
+          * NL[REG] - returns a value from the node_local (shared) control
             block. Takes a case independent region name as an argument.
-          o NLREPL - returns a value from the node_local (shared) control
+          * NLREPL - returns a value from the node_local (shared) control
             block associated with replication. No argument allowed.
-          o PEEK - returns a value based on the supplied argument. Argument
+          * PEEK - returns a value based on the supplied argument. Argument
             is the base address of whatever is being fetched in 0xhhhhhhh
             format where the h's are hex digits.
-          o RIH[REPL] - returns a value from the jnlpool.repl_inst_filehdr
+          * RIH[REPL] - returns a value from the jnlpool.repl_inst_filehdr
             control block. No argument allowed.
-          o RPC[REPL] - returns a value from the recvpool.recvpool_ctl
+          * RPC[REPL] - returns a value from the recvpool.recvpool_ctl
             control block. No argument allowed. Only available when run on a
             non-primary instance.
-          o UHC[REPL] - returns a value from the recvpool.upd_helper_ctl
+          * UHC[REPL] - returns a value from the recvpool.upd_helper_ctl
             control block. No argument allowed. Only available when run on a
             non-primary instance.
-          o UPL[REPL] - returns a value from the recvpool.upd_proc_local
+          * UPL[REPL] - returns a value from the recvpool.upd_proc_local
             control block. No argument allowed. Only available when run on a
             non-primary instance.
 
-     o offset (first integer expression) is a numeric value that specifies
+     * offset (first integer expression) is a numeric value that specifies
        the offset from the address supplied or implied by the the mnemonic
        and argument. Specifying a negative offset results in a BADZPEEKARG
        error. Specifying too large an offset such that unavailable memory is
        specified results in a BADZPEEKRANGE error.
-     o length (second integer expression) is a numeric value that specifies
+     * length (second integer expression) is a numeric value that specifies
        the length of the field to be fetched. Specifying a negative legnth
        results in a BADZPEEKARG error. Specifying a length that exceeds the
        maximum string length results in a MAXSTRLEN error. Specifying too
        large a length such that unavailable memory is specified results in a
        BADZPEEKRANGE error.
-     o format is an optional single case independent character formatting
+     * format is an optional single case independent character formatting
        code for the retrieved data. The formatting codes are:
 
-          o C : returns a character representations of the memory locations;
+          * C : returns a character representations of the memory locations;
             this is the DEFAULT if the fourth argument is not specified.
-          o I : returns a signed integer value - negative values have a
+          * I : returns a signed integer value - negative values have a
             preceding minus sign (-); the length can be 1, 2, 4, or 8 bytes.
-          o U : returns an unsigned integer value - all bits are part of the
+          * U : returns an unsigned integer value - all bits are part of the
             numeric value; the length can be 1, 2, 4, or 8 bytes.
-          o S : returns a character representation of the memory locations
+          * S : returns a character representation of the memory locations
             and the first NULL character found terminates the returned
             string; that is: the specified length is a maximum.
-          o X : returns a hexadecimal value as 0xXXXXXX where XXXXXX is twice
+          * T: Selects a $HOROLOG format for a field of 4 or 8 bytes which is
+            intended for use on fields in UNIX time format (seconds since
+            01/01/1970)
+
+            X : returns a hexadecimal value as 0xXXXXXX where XXXXXX is twice
             the specified length in bytes, so requested length 1 returns 0xXX
             and length 4 returns 0xXXXXXXXX; the length can be 1, 2, 4, or 8
             bytes.
-          o Z : returns a hexadecimal representation of the memory locations
+
+          * Z : returns a hexadecimal representation of the memory locations
             as 'X' does, without regard to endianness, and with no length
             restriction other than max string length.
-          o $ZPEEK() function generates an UNDEF error when VIEW UNDEF is not
+          * $ZPEEK() function generates an UNDEF error when VIEW UNDEF is not
             set and format parameter is specified but is undefined.
 
    **Note**s
 
-     o $ZPEEK() has no UTF-8 checking. It is possible for values returned by
+     * $ZPEEK() has no UTF-8 checking. It is possible for values returned by
        the 'C' and 'S' codes to have invalid UTF-8 values in them. Take care
        when processing values obtained by these codes to either use "VIEW
        NOBADCHAR" when dealing with such values and/or use the $Zxxx()
        flavors of functions like $ZPIECE(), $ZEXTRACT(),etc which also do not
        raise BADCHAR errors when encountering invalid UTF-8 encoded strings.
-     o Note that $ZPEEK() with 8 byte numeric formatting can return numeric
+     * Note that $ZPEEK() with 8 byte numeric formatting can return numeric
        string values that exceed GT.M's current limit of 18 digits of
        precision. If the values are used as strings, the extra digits are
        preserved, but if used arithmetically, the lower precision digits can
        be lost.
-     o When values from replication structures are requested and the
+     * When values from replication structures are requested and the
        structures are not available due to replication not running or, in the
        case of the gtmrecv.* control block base options, if not running on a
        non-primary instance where the gtmrecv.* control are available, a
        ZPEEKNOREPLINFO error is raised.
+     * The JNL[REG] and JBL[REG] mnemonics and characteristics are defined by
+       the running the GTMDefinedTypesInit.m utility, which produces a
+       cross-index in the form:
+
+       gtmtypfldindx(<structure-name>.<field-mnemonic>)=<n>
+
+       where gtmtypes(<structure-name>,<n>,*) nodes contain the field
+       characteristics
 
 2 $ZPrevious()
    $ZPrevious()
@@ -10168,11 +10121,9 @@
    Example:
 
    GTM>job ^Somejob
-
    GTM>set ret=$&gtmposix.signalval("SIGUSR1",.sigusr1) zwrite
    ret=0
    sigusr1=10
-
    GTM>write $zsigproc($zjob,sigusr1)
    0
    GTM>
@@ -10194,13 +10145,9 @@
    GTM>write $ZCHSET
    M
    GTM>set char1="a" ; one byte character
-
    GTM>set char2="c,"; two-byte character
-
    GTM>set char3="*"; three-byte character
-
    GTM>set y=char1_char2_char3
-
    GTM>write $zsubstr(y,1,3)=$zsubstr(y,1,5)
    0
 
@@ -10213,13 +10160,9 @@
    GTM>write $zchset
    UTF-8
    GTM>set char1="a" ; one byte character
-
    GTM>set char2="c,"; two-byte character
-
    GTM>set char3="*"; three-byte character
-
    GTM>set y=char1_char2_char3
-
    GTM>write $zsubstr(y,1,3)=$zsubstr(y,1,5)
    1
 
@@ -10266,13 +10209,9 @@
    Example:
 
    GTM>set hiraganaA=$char(12354) ; $zchar(227,129,130)
-
    GTM>set temp1=$zchar(130)
-
    GTM>set temp2=$zchar(140)
-
    GTM>set tr=$ztranslate(hiraganaA,temp1,temp2)
-
    GTM>w $ascii(tr)
    12364
    GTM>
@@ -10289,6 +10228,15 @@
 
    $ZTRIgger(expr1[,expr2])
 
+   **Note**
+
+   A $ZTRIGGER() action (delete or select) applies to all triggers in all
+   regions matching the specified signature. If the argument specifies an
+   incomplete trigger signature, for example, only the name, the
+   specification may match multiple triggers and apply the delete or select
+   to all of them. FIS recommends you run a select and analyze the scope of
+   the signature before any signature limited delete.
+
 3 Examples_of_$ZTRIGGER()
    Examples of $ZTRIGGER()
 
@@ -10327,8 +10275,8 @@
    definition:
 
    +^a -commands=S -xecute=<<
-     do ^twork1
-     do ^twork2
+    do ^twork1
+    do ^twork2
    >>
 
    Unlike $ztrigger("ITEM"), $ztrigger("FILE") usages require the trigger
@@ -10404,7 +10352,6 @@
 
    GTM>set NG=$char($$FUNC^%HD("200B"))
    GTM>set S=$char(26032)_NG_$CHAR(26033)
-
    GTM>W $ZWidth(STR)
    4
    GTM>
@@ -10418,7 +10365,6 @@
    GTM>write $zwidth("The rain in Spain stays mainly in the plain.")
    44
    GTM>set A="************"
-
    GTM>write $length(A)
    12
    GTM>write $zwidth(A)
@@ -11087,7 +11033,6 @@
      set $etrap="" ; exit if the input isn't valid
      if $length($zcmdline) do @$zcmdline quit
      quit
-
    $ mumps -run foo 'BAR^FOOBAR("hello")'
 
    In this example, GT.M processes the shell command line up to foo and puts
@@ -11430,7 +11375,6 @@
    Example:
 
    set $zinterrupt="do ^interrupthandler($io)"
-
    interrupthandler(currentdev)
           do ^handleinterrupt ; handle the interrupt
           use currentdev      ; restore the device which was current when the interrupt was recognized
@@ -11610,10 +11554,8 @@
    D
     set X=$ZLEVEL
     quit
-
    GTM>do ^zleve
    4
-
    GTM>
 
    This program, executed from Direct Mode, produces a value of 4 for
@@ -11683,20 +11625,14 @@
    Results:
 
    Start with $ZMAXTPTIME=6:
-
    ^X=1,will set ^Y to 3 in 3 seconds...^Y=3...committed.
-
    ^X=2,will set ^Y to 5 in 5 seconds...^Y=5...committed.
-
    ^X=3,will set ^Y to 7 in 7 seconds...
    In $ZTRAP handler. Error was:
    150377322,longtran+7^tptime,%GTM-E-TPTIMEOUT, Transaction timeoutRolled back transaction.
-
    ^X=3,will set ^Y to 9 in 9 seconds...
-
    In $ZTRAP handler. Error was:
    150377322,longtran+7^tptime,%GTM-E-TPTIMEOUT, Transaction timeoutRolled back transaction.
-
    Done TP Timeout test.
 
 2 $ZMOde
@@ -12239,7 +12175,6 @@
    .
    .
    GTM>WRITE $ZSOURCE
-
    subr
 
    Example:
@@ -12249,7 +12184,6 @@
    .
    .
    GTM>WRITE $ZSOURCE
-
    "test"
 
    Example:
@@ -12259,7 +12193,6 @@
    .
    .
    GTM>WRITE $ZSOURCE
-
    /usr/smith/report.txt
 
    Example:
@@ -12353,7 +12286,6 @@
 
    $ export sigusrval=10
    $ /usr/lib/fis-gtm/V6.1-000_x86_64/gtm
-
    GTM>zprint ^ztran
    foo;
      set $ztexit=1
@@ -12382,19 +12314,16 @@
      write "End Transaction",!
      ;do ^srv
      quit
-
    GTM>zprint ^throwint
    throwint
      set $zinterrupt="write !,""interrupt occurred at : "",$stack($stack-1,""PLACE""),! set $ztexit=1"
      if '$zsigproc($job,$ztrnlnm("sigusrval")) write "interrupt sent to process"
      write "***************************************",!!
      quit
-
    GTM>do foo^ztran
    interrupt sent to process
    interrupt occurred at : throwint+3^throwint
    ***************************************
-
    interrupt occurred at : foo+13^ztran
    GTM>
 
@@ -12409,16 +12338,12 @@
    "IF $ZJOBEXAM()"
    GTM>zsystem "ls GTM*"
    ls: No match.
-
    GTM>do bar^ztran
    Begin Transaction
    interrupt sent...
-
    End Transaction
-
    GTM>zsystem "ls GTM*"
    GTM_JOBEXAM.ZSHOW_DMP_3951_1  GTM_JOBEXAM.ZSHOW_DMP_3951_2
-
    GTM>
 
    This uses the default value of $ZINTERRUPT to service interrupts issued to
@@ -13799,7 +13724,6 @@
    Example:
 
    GTM>kill ^a
-
    GTM>zprint ^indepserver
    indepserver;
      read x
@@ -13808,30 +13732,20 @@
      for  do  quit:^quit
      . if $data(^a) write "^a = ",^a,!
      . Hang 5
-
    GTM>set a="test"
-
    GTM>open a:(command="mumps -run ^indepserver>indout":independent)::"pipe"
-
    GTM>use a
-
    GTM>write "instructions",!
-
    GTM>close a
-
    GTM>zsystem "cat indout"
    received = instructions
-
    GTM>set ^a=1
-
    GTM>zsystem "cat indout"
    received = instructions
    ^a = 1
    ^a = 1
    ^a = 1
-
    GTM>s ^quit=1
-
    GTM>zsystem "cat indout"
    received = instructions
    ^a = 1
@@ -14182,18 +14096,18 @@
    CONNSOCKREQ or LOCALSOCKREQ errors, respectively, when those conditions
    are not met.
 
-     o If a numeric targetpid is specified, GT.M matches the value against
+     * If a numeric targetpid is specified, GT.M matches the value against
        the process id ($JOB) of the process receiving the sockets. GT.M uses
        a system service to perform this check on platforms that support it -
        currently: Linux, AIX, and Solaris. On platforms which do not
        implement the service (HP-UX), GT.M ignores the targetpid. If the pids
        do not match, GT.M issues a PEERPIDMISMATCH error and does not
        transfer the sockets.
-     o If a numeric timeout is specified, GT.M sets $TEST to 1 if the
+     * If a numeric timeout is specified, GT.M sets $TEST to 1 if the
        transfer completes within the specified time, and otherwise sets $TEST
        to 0 and does not transfer any of the sockets.
-     o Each handle specifies the name of a socket in the socket pool.
-     o On a successful transfer, GT.M closes the connection of the sending
+     * Each handle specifies the name of a socket in the socket pool.
+     * On a successful transfer, GT.M closes the connection of the sending
        process to the specified and sent sockets. In any case where the
        transfer does not complete, GT.M retains all the sockets in the socket
        pool of the sender.
@@ -14208,22 +14122,22 @@
    CONNSOCKREQ or LOCALSOCKREQ errors, respectively, when those conditions
    are not met.
 
-     o lvar is an unsubscripted local variable name (lvn) which must be
+     * lvar is an unsubscripted local variable name (lvn) which must be
        passed by reference indicated with a period (".") prefix. On
        successful completion, the specified unsubscripted lvn contains the
        handles of the received socket, in the order they were sent, delimited
        with a vertical bar ("|"). GT.M places the sockets in the socket pool,
        so the process can ATTACH them to an appropriate SOCKET device for
        subsequent use.
-     o If a numeric sourcepid is specified, GT.M matches the value against
+     * If a numeric sourcepid is specified, GT.M matches the value against
        the process id ($JOB) of the process sending the sockets. On platforms
        which do not implement the service (HP-UX), GT.M ignores the
        targetpid. If the pids do not match, GT.M issues a PEERPIDMISMATCH
        error and does not transfer the sockets.
-     o If a numeric timeout is specified, GT.M sets $TEST to 1 if the
+     * If a numeric timeout is specified, GT.M sets $TEST to 1 if the
        transfer completes within the specified time, and otherwise sets $TEST
        to 0 and does not transfer the sockets.
-     o If any handles are specified, GT.M assigns the provided handle names
+     * If any handles are specified, GT.M assigns the provided handle names
        to the received sockets in the order in which they appear in the WRITE
        /PASS of the sending process; empty items in the comma delimited
        handle list act to preserve ordering. Where the list provides no
@@ -14249,6 +14163,86 @@
    socket connection itself, the socket handle, and buffered socket data (if
    any).
 
+   WRITE /TLS(option[,[timeout][,tlsid]])
+
+   SOCKET devices support encrypt connections with TLS using an encryption
+   plugin. GT.M ships with a reference implementation of the plugin which
+   uses OpenSSL and also supports TLS of replication stream. OpenSSL options
+   are controlled by a configuration file. The WRITE /TLS command activates
+   this feature for connected sockets. Because this functionality has a wide
+   variety of user stories (use cases) and has substantial complexity,
+   although the code appears robust, we are not confident that we have
+   exercised a sufficient breadth of use cases in testing. Also we may make
+   changes in future releases that are not entirely backwards compatible. We
+   encourage you to use with this facility in development and testing, and to
+   provide us with feedback. If you are an FIS customer and wish to use this
+   in production, please contact us beforehand to discuss your use case(s).
+
+     * option is "server" or "client" indicating which TLS role to assume or
+       "renegotiate" which is used by a server to request a new handshake to
+       reevaluate the client credentials. The server role requires a
+       certificate specified in the configuration file section with the label
+       matching tlsid. The client role may require a certificate depending on
+       the OpenSSL options. If the argument specifies a timeout, GT.M sets
+       $TEST to 1 if the command successfully completed or to 0 if it timed
+       out. $DEVICE provides status information in case of an error. ZSHOW
+       "D" includes "TLS" in the second line of the output for an encrypted
+       socket.
+     * Note that SOCKET device actions may produce the following errors:
+       TLSDLLOPEN, TLSINIT, TLSCONVSOCK, TLSHANDSHAKE, TLSCONNINFO,
+       TLSIOERROR, and TLSRENEGOTIATE.
+
+   The TLS plugin uses OpenSSL options in the configuration file specified
+   under the tls: label as the default for all TLS connections and under the
+   specific labels to override the defaults for corresponding connections.
+   GT.M recognizes the following for both sockets:
+
+     * The cipher-list option specifies which cryptographic algorithms to
+       use. The format of this option is described by the OpenSSL ciphers man
+       page. An empty string uses a default value of
+       "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" for replication connections and
+       the OpenSSL default cipher list for socket connections.
+     * The ssl_options, documented in the man page for SSL_set_options,
+       modify the default behavior of OpenSSL. When specifying multiple
+       options, separate them with acolons (:) delimiter. The ssl-options
+       specified in a labeled section add to, or override, those specified at
+       the "tls" level. An exclamation mark ("!") preceding an option in a
+       labeled section disables any default for that option specified at the
+       tls: level; for example:
+
+       tls: {
+        ssl-options: "SSL_OP_CIPHER_SERVER_PREFERENCE";
+        mylabel: {
+        ssl-options: "!SSL_OP_CIPHER_SERVER_PREFERENCE";
+        };
+        }
+
+     * The verify-mode option specifies how OpenSSL verifies certificates. If
+       no verify-mode is specified, a socket connection defaults to
+       SSL_VERIFY_NONE. We have tested with SSL_VERIFY_PEER and
+       SSL_VERIFY_NONE See the man page for SSL_set_verify for details.
+       SSL_VERIFY_PEER has two additional flags which modify verification
+       only for the server role; when adding them to the option string, use
+       the colon (:) delimiter.
+     * A verify-depth option specified in a labeled section applies to
+       connections associated with that section.
+
+   When placing the private key for a certificate at the beginning of the
+   certificate file, you may omit the "key" item from the configuration file.
+   The format of the combined file is:
+
+   -----BEGIN RSA PRIVATE KEY-----
+    [encoded key]
+    -----END RSA PRIVATE KEY-----
+    [empty line]
+    -----BEGIN CERTIFICATE-----
+    [encoded certificate]
+    -----END CERTIFICATE-----
+    [empty line]
+
+   GT.M buffers WRITEs to TLS enabled sockets until a subsequent USE :FLUSH,
+   WRITE !, WRITE #, or an internal 400 millisecond timer expires.
+
 3 Socket_Device_Operation
    Socket Device Operation
 
@@ -14971,7 +14965,6 @@
 
    GTM>file1="foo.txt"
    GTM>open file1:newversion:recordsize=5000
-
    GTM>
 
    This example creates a new version of sequential file foo.txtwith
@@ -15166,6 +15159,10 @@
 
    REWIND positions the file pointer of a sequential disk.
 
+   When $PRINCIPAL identifies a device that supports REWIND, the REWIND or
+   INREWIND device parameters perform a REWIND of the input and OUTREWIND
+   performs a REWIND of the output.
+
    By default, OPEN does not REWIND.
 
    Example:
@@ -15954,15 +15951,12 @@
    Example:
 
    GTM>set tcp="seerv" open tcp:(listen="6321:TCP":attach="serv")::"SOCKET"
-
    GTM>zshow "D"
    /dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
    seerv OPEN SOCKET TOTAL=1 CURRENT=0
            SOCKET[0]=serv DESC=3 LISTENING PASSIVE NOTRAP PORT=6321
                      ZDELAY ZBFSIZE=1024 ZIBFSIZE=87380 NODELIMITER
-
    GTM>set tcp="seerv" o tcp:(listen="6322:TCP":attach="serv2")::"SOCKET"
-
    GTM>zshow "D"
    /dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
    seerv OPEN SOCKET TOTAL=2 CURRENT=1
@@ -15977,7 +15971,6 @@
    The following command moves the "serv" socket to the "socketpool" device.
 
    GTM>use tcp:detach="serv"
-
    GTM>use 0 zshow "D"
    /dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
    seerv OPEN SOCKET TOTAL=1 CURRENT=0
@@ -16346,9 +16339,7 @@
    Example:
 
    GTM>set tcp="seerv" open tcp:(listen="6321:TCP":attach="serv")::"SOCKET"
-
    GTM>use tcp:listen="6322:TCP"
-
    GTM>use 0 zshow "D"
    /dev/pts/9 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=80 LENG=24
    seerv OPEN SOCKET TOTAL=2 CURRENT=1
@@ -17861,7 +17852,6 @@
    #include <stdio.h>
    #include <string.h>
    #include "gtmxc_types.h"
-
    void gtm_pre_alloc_a (int count, char *arg_prealloca)
    {
        strcpy(arg_prealloca, "New Message");
@@ -17953,21 +17943,15 @@
    % cat /usr/joe/callback.xc
    /usr/lib/callback.sl
    init: void init_callbacks(I:gtm_pointertofunc_t, I:gtm_pointertofunc_t)
-
    % gtm
    GTM> do &.init(4,5)
    GTM>
-
    % cat /usr/joe/callback.c
    #include <stdio.h>
    #include <stdlib.h>
-
    #include "gtmxc_types.h"
-
    void* (*malloc_fn)(int);
-
    void (*free_fn)(void*);
-
    void init_callbacks(int count, void* (*m)(int), void (*f)(void*))
    {
        malloc_fn = m;
@@ -18817,7 +18801,6 @@
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
    };
-
    long
    gtm_ac_xform (in, level, out, outlen)
         gtm_descriptor *in;    /* the input string */
@@ -18881,7 +18864,6 @@
    224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
    240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
    };
-
    long gtm_ac_xback (in, level, out, outlen)
         gtm_descriptor *in;    /* the input string */
         int level;            /* the subscript level */
@@ -18958,7 +18940,6 @@
    Example:
    #include "gtm_descript.h"
    #define MYAPP_WRONGVERSION 20406080    /* User condition */
-
    gtm_ac_verify (type, ver)
         unsigned char type, ver;
    {
@@ -19028,7 +19009,6 @@
    Example:
 
    GTM>kill ^G
-
    GTM>write $select($$set^%GBLDEF("^G",0,3):"ok",1:"failed")
    ok
    GTM>
@@ -19277,7 +19257,6 @@
    compile-time error with the message:
 
    S =B+C ^-----
-
    At column 4, line 7, source module ADD2
     Variable expected in this context
 
@@ -20044,3 +20023,20 @@
    each KILL command. GT.M does not check nodes in sub-trees to see whether
    they have matching triggers.
 
+3 Accessing_Xecute_Source_Code
+   Accessing Xecute Source Code
+
+   ZPRINT/$TEXT()/ZBREAK recognize both a runtime-disambiguator, delimited
+   with a hash-sign (#), and a region-disambiguator, delimited by a slash(/);
+   previously they supported only the runtime-disambiguator. ZPRINT and
+   ZBREAK treat a trigger-not-found case as a TRIGNAMENF error, while $TEXT()
+   returns the empty string. When their argument contains a
+   region-disambiguator, these features ignore a null runtime-disambiguator.
+   When their argument does not contain a region-disambiguator, these
+   features act as if runtime-disambiguator is specified, even if it has an
+   empty value. When an argument specifies both runtime-disambiguator and
+   region-disambiguator and the runtime-disambiguator identifies a trigger
+   loaded from a region different from the specified region, or the
+   region-disambiguator identifies a region which holds a trigger that is not
+   mapped by $ZGBLDIR, these features treat the trigger as not found.
+
diff --git a/sr_port/mupip.hlp b/sr_port/mupip.hlp
index ae174d9..2516519 100644
--- a/sr_port/mupip.hlp
+++ b/sr_port/mupip.hlp
@@ -546,7 +546,6 @@
    $ mupip backup -database -noonline "*" bkup
    DB file /home/gtmnode1/gtmuser1/mumps.dat backed up in file bkup/mumps.dat
    Transactions up to 0x00000000000F42C3 are backed up.
-
    BACKUP COMPLETED.
 
    This command creates a disk-to-disk backup copy of all regions of the
@@ -572,7 +571,6 @@
    $ mupip backup -online DEFAULT bkup
    DB file /gtmnode1/gtmuser1/mumps.dat backed up in file bkup/mumps.dat
    Transactions up to 0x00000000483F807C are backed up.
-
    BACKUP COMPLETED.
 
    This command creates a backup copy of the DEFAULT region of the current
@@ -599,7 +597,6 @@
    DB file /home/reptiles/mumps.dat incrementally backed up in file bkup1921onwards/mumps.dat
    6 blocks saved.
    Transactions from 0x00000000000F4351 to 0x00000000000F4352 are backed up.
-
    BACKUP COMPLETED.
 
    The first command sets a reference point and creates a backup copy of the
@@ -614,7 +611,6 @@
    DB file /gtmnode1/gtmuser1/mumps.dat incrementally backed up in file bkup/mumps.dat
    5 blocks saved.
    Transactions from 0x0000000000000001 to 0x0000000000000003 are backed up.
-
    BACKUP COMPLETED.
 
    This command copies all in-use blocks of the DEFAULT region of the current
@@ -765,9 +761,7 @@
 
    $ mupip endiancvt mumps.dat -outdb=mumps_cvt.dat
    Converting database file mumps.dat from LITTLE endian to BIG endian on a LITTLE endian system
-
    Converting to new file mumps_cvt.dat
-
    Proceed [yes/no] ?
 
    This command detects the endian format of mumps.dat and converts it to the
@@ -807,7 +801,9 @@
    Specifies the number of GDS database blocks by which MUPIP should extend
    the file. GDS files use additional blocks for bitmaps. MUPIP EXTEND adds
    the specified number of blocks plus the bitmap blocks required as
-   overhead. The format of the BLOCK qualifier is:
+   overhead.
+
+   The format of the BLOCK qualifier is:
 
    -BLOCKS=data-blocks-to-add
 
@@ -1256,6 +1252,16 @@
    Specifies that the reported key is for the Receive Pool of the instance
    created by the current Global Directory.
 
+2 HASH
+   HASH
+
+   Uses a 128 bit hash based on the MurmurHash3 algorithm to provide provides
+   the hash of source files from the command line.
+
+   The format of the MUPIP HASH command is:
+
+   MUPIP HASH <file-names>
+
 2 INTEG
    INTEG
 
@@ -1394,9 +1400,6 @@
 
    -BL[OCK]=block-number
 
-     o Block numbers are displayed in an INTEG error report or by using DSE.
-     o Incompatible with: -SUBSCRIPT and -TN_RESET
-
 3 BRief
    BRief
 
@@ -1712,7 +1715,6 @@
    A sample output from the above command follows:
 
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               5           4.150            NA
    Index              18            1151          77.018             1
    Data             1137           94189          97.894          1030
@@ -1733,9 +1735,7 @@
    sample output from the above command follows:
 
    No errors detected by integ.
-
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               2           2.490            NA
    Index               1               1           2.343             1
    Data                1               3           6.738             1
@@ -1753,7 +1753,6 @@
    No errors detected by fast integ.
 
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               2           2.490            NA
    Index               1               1           2.343             1
    Data                1              NA              NA            NA
@@ -1771,16 +1770,12 @@
    Level          Blocks         Records          % Used      Adjacent
        1               1               1           2.343           NA
        0               1               1           2.636           NA
-
    Global variable ^Dinosaur
    Level          Blocks         Records          % Used      Adjacent
        1               1               6           8.398             1
        0               6             500          83.902             6
-
    No errors detected by integ.
-
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               2           2.490            NA
    Index               1               6           8.398             1
    Data                6             500          83.902             6
@@ -1855,15 +1850,11 @@
    The format of the LOAD command is:
 
    L[OAD]
-   [
-    -BE[GIN]=integer
-    -E[ND]=integer
-    -FI[LLFACTOR]=integer
-    -FO[RMAT]={GO|B[INARY]|Z[WR]]}
-    -[O]NERROR={STOP|PROCEED|INTERACTIVE}
-    -S[TDIN]
-   ]
-    file-name
+   [-BE[GIN]=integer -E[ND]=integer
+   -FI[LLFACTOR]=integer
+   -FO[RMAT]={GO|B[INARY]|Z[WR]]}
+   -[O]NERROR={STOP|PROCEED|INTERACTIVE}
+   -S[TDIN]] file-name
 
    **Caution**
 
@@ -1871,21 +1862,21 @@
    an application is running may result in an inconsistent application state
    for the database.
 
-     o MUPIP LOAD uses the Global Directory to determine which database files
+     * MUPIP LOAD uses the Global Directory to determine which database files
        to use.
-     o LOAD supports user collation routines.
-     o LOAD takes its input from the file defined by the file-name
-     o LOAD may take its input from a UNIX file on any device that supports
+     * LOAD supports user collation routines.
+     * LOAD takes its input from the file defined by the file-name
+     * LOAD may take its input from a UNIX file on any device that supports
        such files.
-     o MUPIP LOAD command considers a sequential file as encoded in UTF-8 if
+     * MUPIP LOAD command considers a sequential file as encoded in UTF-8 if
        the environment variable gtm_chset is set to UTF-8. Ensure that MUPIP
        EXTRACT commands and corresponding MUPIP LOAD commands execute with
        the same setting for the environment variable gtm_chset.
-     o For information on loading with an M "percent utility," refer to the
+     * For information on loading with an M "percent utility," refer to the
        %GI section of the "M Utility Routines" chapter in GT.M Programmer's
        Guide. LOAD is typically faster, but the %GI utility can be
        customized.
-     o Press <CTRL-C> to produce a status message from LOAD. Entering
+     * Press <CTRL-C> to produce a status message from LOAD. Entering
        <CTRL-C> twice in quick succession stops LOAD. A LOAD that is manually
        stopped or stops because of an internal error is incomplete and may
        lack application level integrity, but will not adversely affect the
@@ -1911,8 +1902,11 @@
 3 FOrmat
    FOrmat
 
-   Specifies the format of the input file. The format must match the actual
-   format of the input file for LOAD to operate.
+   Specifies the format of the input file. If the format of the input file is
+   not specified, MUPIP LOAD automatically detects file format
+   (BINARY/ZWR/GO) based on the file header of the input file. If format is
+   specified, it must match the actual format of the input file for LOAD to
+   operate.
 
    The format codes are:
 
@@ -1920,15 +1914,17 @@
    B[INARY] - Binary format
    Z[WR] - ZWRITE format
 
-     o By default, LOAD uses FORMAT=ZWR.
-     o -FORMAT=GO expects the data in record pairs. Each global node requires
+     * By default, LOAD uses FORMAT=ZWR.
+     * -FORMAT=GO expects the data in record pairs. Each global node requires
        one record for the key and one for the data.
-     o -FORMAT=ZWR expects the data for each global node in a single record.
-     o -FORMAT=BINARY only applies to Greystone Database Structure (GDS)
+     * -FORMAT=ZWR expects the data for each global node in a single record.
+     * -FORMAT=BINARY only applies to Greystone Database Structure (GDS)
        files. A BINARY format file loads significantly faster than a GO or
        ZWR format file. -FORMAT=BINARY works with data in a proprietary
        format. -FORMAT=BINARY has one header record, therefore LOAD
        -FORMAT=BINARY starts active work with record number two (2).
+     * MUPIP LOAD detects file format (BINARY/ZWR/GO) based on the file
+       header of extract files from MUPIP EXTRACT, ^%GO and DSE.
 
 3 BEgin
    BEgin
@@ -1944,14 +1940,14 @@
    Always consider the number of header records for choosing a -BEGIN point.
    See FORMAT qualifier for more information.
 
-     o For -FORMAT=GO input, the value is usually an odd number. As
+     * For -FORMAT=GO input, the value is usually an odd number. As
        -FORMAT=BINARY requires important information from the header, this
        type of load requires an intact file header regardless of the -BEGIN
        value.
-     o For -FORMAT = ZWR input, each record contains a complete set of
+     * For -FORMAT = ZWR input, each record contains a complete set of
        reference and data information. The beginning values are not
        restricted, except to allow two records for the header.
-     o By default, LOAD starts at the beginning of the input file.
+     * By default, LOAD starts at the beginning of the input file.
 
 3 End
    End
@@ -1977,14 +1973,14 @@
 
    -FI[LL_FACTOR]=integer
 
-     o Reserves room and avoid unnecessary block split to accommodate the
+     * Reserves room and avoid unnecessary block split to accommodate the
        forecasted growth in a global variable that may experience significant
        rate of additions over a period.
-     o Users having database performance issues or a high rate of database
+     * Users having database performance issues or a high rate of database
        updates must examine the defined FILL_FACTORs. Unless the application
        only uses uniform records, which is not typical for most applications,
        FILL_FACTORs do not work precisely.
-     o By default, LOAD uses -FILL_FACTOR=100 for maximum data density.
+     * By default, LOAD uses -FILL_FACTOR=100 for maximum data density.
 
    **Note**
 
@@ -2001,9 +1997,9 @@
 
    -[O]NERROR={STOP|PROCEED|INTERACTIVE}
 
-     o STOP causes MUPIP LOAD to exit immediately.
-     o PROCEED proceeds to the next record.
-     o PROMPTS prompts to continue or stop.
+     * STOP causes MUPIP LOAD to exit immediately.
+     * PROCEED proceeds to the next record.
+     * PROMPTS prompts to continue or stop.
 
    By default MUPIP LOAD exits on encountering an error.
 
@@ -2040,10 +2036,11 @@
    output from the above command follows:
 
    GT.M MUPIP EXTRACT
-   02-MAR-2011  18:25:47 ZWR
+   02-MAR-2011 18:25:47 ZWR
    Beginning LOAD at record number: 5
-
-   LOAD TOTAL Key Cnt: 6  Max Subsc Len: 7  Max Data Len: 1
+   LOAD TOTAL Key Cnt: 6
+   Max Subsc Len: 7
+   Max Data Len: 1
    Last LOAD record number: 10
 
    Example:
@@ -2060,6 +2057,65 @@
 
    These commands loads the extract file big.glo using -stdin.
 
+2 RCTLDUMP
+   RCTLDUMP
+
+   Reports information related to relinkctl files and their associated shared
+   memory segments. The format of the MUPIP RCTLDUMP command is:
+
+   MUPIP RCTLDUMP [dir1]
+
+   If the optional parameter dir1 is not specified, MUPIP RCTLDUMP dumps
+   information on all its active auto-relink-enabled directories (those with
+   with a *-suffix) identified by $gtmroutines. With a directory path
+   specified for dir1, MUPIP RCTLDUMP reports information on the one
+   directory. An example output follows. It lists the full path of the Object
+   directory; its corresponding relinkctl file name; the number of routines
+   currently loaded in this relinkctl file; the number of processes including
+   the reporting MUPIP process that have this Relinkctl file open; the shared
+   memory id and length of the Relinkctl shared memory segment; one or more
+   Rtnobj shared memory segment(s); and a listing of all the routine names
+   loaded in this file (lines starting with rec#...).
+
+     o The Rtnobj shared memory line : All the length fields are displayed in
+       hexadecimal. shmlen is the length of the allocated shared memory
+       segment in bytes. shmused is the length that is currently used.
+       shmfree is the length available for use. objlen is the total length of
+       all the objects currently loaded in this shared memory. As GT.M
+       allocates blocks of memory with sizes rounded-up to an integer power
+       of two bytes, shmused is always greater than objlen; for example with
+       an objlen of 0x1c0, the shmused is 0x200.
+     o Lines of the form rec#... indicate the record # in the relinkctl file.
+       Each relinkctl file can store a maximum of 1,000,000 records, i.e.,
+       the maximum number of routines in a directory with auto-relink enabled
+       is one million. Each record stores a routine name (rtnname:), the
+       current cycle # for this object file record entry (cycle:) which gets
+       bumped on every ZLINK or ZRUPDATE command, the hash of the object file
+       last loaded for this routine name (objhash:), the # of different
+       versions of object files loaded in the Rtnobj shared memory segments
+       with this routine name (numvers:), the total byte-length of the one or
+       more versions of object files currently loaded with this routine name
+       (objlen:), the total length used up in shared memory for these object
+       files where GT.M allocates each object file a rounded-up perfect
+       2-power block of memory (shmlen:).
+
+   Given a relinkctl file name, one can find the corresponding directory path
+   using the Unix "strings" command on the Relinkctl file. For example,
+   "strings /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002",
+   corresponding to the above MUPIP RCTLDUMP output example, would output
+   "/obj" the corresponding directory name.
+
+   Example:
+
+   $ mupip rctldump .
+   Object Directory         : /obj
+   Relinkctl filename       : /tmp/gtm-relinkctl-f0938d18ab001a7ef09c2bfba946f002
+   # of routines            : 1
+   # of attached processes  : 2
+   Relinkctl shared memory  : shmid: 11534344  shmlen: 0x57c6000
+   Rtnobj shared memory # 1 : shmid: 11567113  shmlen: 0x100000  shmused: 0x200  shmfree: 0xffe00  objlen: 0x1c0
+       rec#1: rtnname: abcd  cycle: 1  objhash: 0xedbfac8c7f7ca357  numvers: 1  objlen: 0x1c0  shmlen: 0x200
+
 2 REORG
    REORG
 
@@ -2140,11 +2196,8 @@
    This command produces an output like the following:
 
    Integ of region DEFAULT
-
    No errors detected by integ.
-
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               2           2.490            NA
    Index              29            2528          95.999             1
    Data             2500           10000          82.811          2499
@@ -2159,7 +2212,6 @@
    At the GT.M prompt, execute the following command sequence:
 
    GTM>for i=1:2:10000 s ^x(i)=$justify(i,200)
-
    GTM>for i=2:2:10000 set ^x(i)=$justify(i,200)
 
    Then, execute the following command:
@@ -2169,11 +2221,8 @@
    This command produces an output like the following:
 
    Integ of region DEFAULT
-
    No errors detected by integ.
-
    Type           Blocks         Records          % Used      Adjacent
-
    Directory           2               2           2.490            NA
    Index             153            3902          29.211            57
    Data             3750           10000          55.856          1250
@@ -2500,6 +2549,7 @@
 
    -F[ile]
    -R[egion]=region-list
+   -RELinkctl [dir1]
 
    If the RUNDOWN command does not specify either -File or -Region, it checks
    all the IPC resources (shared memory) on the system and if they are
@@ -2515,6 +2565,24 @@
 
    Incompatible with: -REGION
 
+3 Relinkctl
+   Relinkctl
+
+   Cleans up orphaned Relinkctl files. FIS strongly recommends avoiding
+   actions that tend to make such cleanup necessary - for example, kill -9 of
+   GT.M processes or ipcrm -m of active Relinkctl and/or Rtnobj shared memory
+   segments.
+
+   If the optional dir1 is not specified, MUPIP RUNDOWN -RELINKCTL examines
+   the environment variable $gtmroutines, attempts to verify and correct
+   their attach counts and runs down all its inactive auto-relink-enabled
+   directories (those with with a *-suffix). Alternatively, one can specify a
+   directory path for the parameter dir1 and MUPIP RUNDOWN -RELINKCTL treats
+   it as an auto-relink-enabled directory and runs down the resources
+   associated with this one directory. It prints a RLNKCTLRNDWNSUC message on
+   a successful rundown and a RLNKCTLRNDWNFL message on a failure (usually
+   because live processes are still accessing the Relinkctl file).
+
 3 Region
    Region
 
@@ -2799,7 +2867,6 @@
    all regions.
 
    $ mupip set -version=V4 -file mumps.dat
-
    Database file mumps.dat now has desired DB format V4
 
    This example sets the block format to V4 for all subsequent new blocks in
@@ -2808,7 +2875,6 @@
    Example:
 
    $ mupip set -version=v6 -file mumps.dat
-
    Database file mumps.dat now has desired DB format V5
 
    This example sets the block format to V6 for all subsequent new blocks in
@@ -2999,8 +3065,8 @@
    Examines or loads trigger definitions. The format of the MUPIP TRIGGER
    command is:
 
-   TRIGGER {-TRIG[GERFILE]=<trigger_definitions_file> [-NOPR[OMPT]]|
-   [-SELE[CT][=name-list|*][<select-output-file>]}
+   TRIGGER {-TRIG[GERFILE]=<trigger_definitions_file>
+   [-NOPR[OMPT]]|[-SELE[CT][=name-list|*][<select-output-file>]|-UPGRADE}
 
    Before you run the MUPIP TRIGGER command:
 
@@ -3020,19 +3086,19 @@
 
    -TRIG[GERFILE]=<trigger_definitions_file> [-NOPR[OMPT]]
 
-     o
-     o A MUPIP TRIGGER -TRIGGERFILE operation occurs within a transaction
+     *
+     * A MUPIP TRIGGER -TRIGGERFILE operation occurs within a transaction
        boundary, therefore, if even one trigger from the trigger definition
        file fails to parse correctly, MUPIP TRIGGER rolls back the entire
        trigger definition file load. MUPIP TRIGGER operations have an
        implicit timeout of zero (0), meaning the read must succeed on the
        first try or the command will act as if it received no input.
-     o MUPIP TRIGGER -TRIGGERFILE ignores blank lines and extra whitespace
+     * MUPIP TRIGGER -TRIGGERFILE ignores blank lines and extra whitespace
        within lines. It treats lines with a semi-colon in the first position
        as comments and ignores their content.
-     o MUPIP TRIGGER compiles the XECUTE action string and rejects the load
+     * MUPIP TRIGGER compiles the XECUTE action string and rejects the load
        if the compilation has errors.
-     o Always specify the same value for the environment variable gtm_chset
+     * Always specify the same value for the environment variable gtm_chset
        during loading and executing triggers. If you specify different values
        of gtm_chset during loading and executing triggers, MUPIP TRIGGER
        generates a run-time error (TRIGINVCHSET). GT.M does not prevent a
@@ -3042,13 +3108,17 @@
        for all database updates, should be to ensure that you provide the
        same value for gtm_chset during load compilation and run-time
        compilation.
-     o MUPIP TRIGGER replicate trigger definitions as logical actions from an
+     * MUPIP TRIGGER replicate trigger definitions as logical actions from an
        originating/primary instance to a replicating/secondary instance based
        on LGTRIG journal records. This permits the instances to have
        different sets of triggers and differing database layouts (for
        example, different # of regions, different block sizes, different
        maximum-record-size, and so on).
-     o Incompatible with: -SELECT
+     * MUPIP TRIGGER limits trigger expression source lines to 80 characters
+       including a trailing ellipsis to indicate there was more text, and
+       they also replace any non-graphic characters with a dot (.)
+
+     * Incompatible with: -SELECT
 
    **Note**
 
@@ -3063,17 +3133,21 @@
    produces a list of the current triggers for a comma-separate list of
    global variables or trigger names. The format of the SELECT qualifier is:
 
-   -SELE[CT][=name-list[*]|*][ <select-output-file>]
+   -SELE[CT][=name-list*][ <select-output-file>]
 
-    1. Name-list can include global names, delimited with a leading caret
+     * Name-list can include global names, delimited with a leading caret
        (^), and/or trigger names (user-defined or auto-generated) with no
        leading caret. You can specify a trailing asterisk(*) with either.
-    2. With no arguments specified, GT.M treats -SELECT as -SELECT="*" and
+     * With no arguments specified, GT.M treats -SELECT as -SELECT="*" and
        extracts a list of all current triggers.
-    3. Optionally, you can specify a file name to redirect the output of the
+     * Optionally, you can specify a file name to redirect the output of the
        command. If you do not specify a file name, MUPIP TRIGGER prompts for
        a file name. If you respond with an empty string (RETURN), MUPIP
        TRIGGER directs the output to STDOUT.
+     * MUPIP TRIGGER -SELECT displays all output including errors on STDOUT.
+     * For Trigger definition reporting operations, $ZTRIGGER("SELECT") and
+       MUPIP TRIGGER -SELECT, return a non-zero exit status when their
+       selection criteria encounter an error in the middle of the select.
 
    **Note**
 
@@ -3094,6 +3168,28 @@
    pound-sign (#) starts with a 0 (which is an impossible auto-generated
    trigger name).
 
+   UPGRADE
+
+   Upgrades older trigger definitions into current format.
+
+   The format of the UPGRADE qualifier is:
+
+   -UPGRADE
+
+   If GT.M encounters an old trigger definition it produces a NEEDTRIGUPGRD
+   message. To preserve the possibility of a straightforward downgrade to an
+   earlier version, perform a select "*" action with MUPIP TRIGGER (or
+   $ZTRIGGER() and save the result. Note that TRIGGER -UPGRADE assumes that
+   the existing trigger definitions are properly defined; if the prior
+   release has produced defective triggers delete them with a wild-card
+   ("*"), do the MUPIP TRIGGER -UPGRADE and redefine the triggers in the new
+   release. In the event of a downgrade, delete "*" all triggers before the
+   downgrade and insert the saved version from before the upgrade. Attempting
+   to perform a MUPIP TRIGGER -UPGRADE on a database without write
+   authorization to the database produces a TRIGMODREGNOTRW error. The
+   -UPGRADE qualifier is not compatible with any other MUPIP TRIGGER
+   qualifier.
+
 3 Examples
    Examples
 
@@ -3136,7 +3232,7 @@
        This command displays the triggers. A sample output looks like the
        following:
 
-       ;trigger name: ValidateAccount#  cycle: 1
+       ;trigger name: ValidateAccount# cycle: 1
        +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!"""
 
    To modify an existing trigger for global node ^Acct("ID"):
@@ -3159,7 +3255,7 @@
     2. Specify trigger_mod.trg as the output file. This file contains entries
        like the following:
 
-       ;trigger name: ValidateAccount#  cycle: 1
+       ;trigger name: ValidateAccount# cycle: 1
        +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!"""
 
     3. Using your editor, open trigger_mod.trg and change + (plus) to -
@@ -3169,8 +3265,10 @@
        new one in the same transaction (Atomic). The trigger_mod.trg file
        should have entries like:
 
-       ;trigger name: ValidateAccount#  cycle: 1-^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Earth!"""
-       ;trigger name: ValidateAccount#+^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Mars!"""
+       ;trigger name: ValidateAccount# cycle: 1
+       -^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Earth!"""
+       ;trigger name: ValidateAccount#
+       +^Acct("ID") -name=ValidateAccount -commands=Set -xecute="Write ""Hello Mars!"""
 
     4. Execute a command like the following:
 
@@ -3200,7 +3298,7 @@
     2. Specify trigger_delete.trg as the output file. This file contains
        entries like the following:
 
-       ;trigger name: ValidateAccount#  cycle: 3
+       ;trigger name: ValidateAccount# cycle: 3
        +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!"""
 
     3. Using your editor, change + (plus) to - (minus) for the trigger
@@ -3240,7 +3338,7 @@
     3. Respond with an empty string (Press Enter). Confirm that the trigger
        summary report contains an entry like the following:
 
-       ;trigger name: ValidateAccount#  cycle: 3
+       ;trigger name: ValidateAccount# cycle: 3
        +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!"""
 
     4. Now, execute a command like the following:
@@ -4098,7 +4196,7 @@
 
    To avoid broken transaction or lost transaction processing and instead
    extract all journal records into one file, use the control qualifier
-   -FENCES=NONE. FIS strongly recommended against using  -FENCES=NONE if
+   -FENCES=NONE. FIS strongly recommended against using -FENCES=NONE if
    -RECOVER/-ROLLBACK is also specified.
 
 4 RECover
@@ -4377,13 +4475,11 @@
        -------------------------------------------------------------------------------
        SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
        -------------------------------------------------------------------------------
-
        Journal file name       /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
        Journal file label      GDSJNL23
        Database file name      /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.dat
         Prev journal file name /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl_2012310190106
         Next journal file name
-
         Before-image journal                      ENABLED
         Journal file header size                    65536 [0x00010000]
         Virtual file size                            2048 [0x00000800] blocks
@@ -4411,15 +4507,11 @@
         Turn Around Point Time                          0
         Start Region Sequence Number                    1 [0x0000000000000001]
         End Region Sequence Number                      1 [0x0000000000000001]
-
        Process That Created the Journal File:
-
        PID        NODE        USER     TERM JPV_TIME
        ---------------------------------------------------------
        0000006706 jdoe-laptop jdoe    0    2012/11/06 17:30:33
-
        Process That First Opened the Journal File:
-
        PID        NODE        USER     TERM JPV_TIME
        ---------------------------------------------------------
        0000006706 jdoe-laptop jdoe    0    2012/11/06 17:30:33
@@ -4438,7 +4530,6 @@
        -------------------------------------------------------------------------------
        SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
        -------------------------------------------------------------------------------
-
        Record type    Count
        ----------------------
           *BAD*          0
@@ -4473,7 +4564,6 @@
           TZTRI          0
           UZTRI          0
           TRUNC          0
-
        %GTM-S-JNLSUCCESS, Show successful
        %GTM-S-JNLSUCCESS, Verify successful
        %GTM-I-MUJNLSTAT, End processing at Tue Nov  6 17:42:21 2012
@@ -4482,7 +4572,6 @@
    stored in the journal file header (the output is one long line).
 
    $ mupip journal -show -backward mumps.mjl 2>&1 | grep hash
-
    Journal file hash F226703EC502E975784
    8EEC733E1C3CABE5AC146C60F922D0E7D7CB5E
    2A37ABA005CE98D908B219249A0464F5BB622B72F5FDA
@@ -5667,6 +5756,7 @@
     <soft tries period>, <alert time>, <heartbeat period>,
     <max heartbeat wait>]
     -instsecondary=<replicating instance name>
+    [-[no]jnlf[ileonly]]
     -log=<log file name> [-log_interval=<integer>]
     {-rootprimary|-propagateprimary} [{-updok|-updnotok}]
     [-cmplvl=<compression level>]
@@ -5880,6 +5970,16 @@
    This command starts the Source Server for the originating instance with
    instance B as its replicating instance.
 
+   -[no]jnlfileonly
+
+   Forces the Source Server to read transactions from journal files instead
+   of journal pool shared memory. When combined with the SYNC_IO journal
+   option, this feature delays replication of transactions until their
+   journal records are hardened to disk. This may be useful when replicating
+   to a supplementary instance, as a crash and rollback on the primary could
+   otherwise necessitate a rollback of local updates on the receiving
+   instance. The default is -NOJNLFILEONLY.
+
    -rootprimary
 
    Assign the current instance as the originating instance. You can specify
@@ -6137,9 +6237,10 @@
 
    -timeout=<timeout in seconds>
 
-   Specifies the time (in seconds) the Source Server should wait before
-   shutting down. If you do not specify -timeout, the default timeout period
-   is 120 seconds. If you specify -timeout=0 , shutdown occurs immediately.
+   Specifies the time (in seconds) the shutdown command should wait before
+   signaling the Source Server to shut down. If you do not specify -timeout,
+   the default timeout period is 120 seconds. If you specify -timeout=0 ,
+   shutdown occurs immediately.
 
 2 Activate_Passive_Source_Server
    Activate Passive Source Server
@@ -6283,13 +6384,10 @@
    Example:
 
    $ mupip replic -source -checkhealth -inst=INSTB
-
    Fri May 21 15:26:18 2010 : Initiating CHECKHEALTH operation on source server pid [15511] for secondary
    instance name [INSTB]
    PID 15511 Source server is alive in ACTIVE mode
-
    $ mupip replic -source -checkhealth -inst=INSTB
-
    Fri May 21 15:29:52 2010 : Initiating CHECKHEALTH operation on source server pid [0] for secondary
    instance name [INSTB]
    PID 0 Source server is NOT alive
@@ -7314,15 +7412,16 @@
 
    Copyright 2014
 
-   Fidelity Information Services, Inc. All rights reserved.
+   Fidelity National Information Services, Inc. and/or its subsidiaries. All
+   rights reserved.
 
    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or any
    later version published by the Free Software Foundation; with no Invariant
    Sections, no Front-Cover Texts and no Back-Cover Texts.
 
-   GT.M(TM) is a trademark of Fidelity Information Services, Inc. Other
-   trademarks are the property of their respective owners.
+   GT.M(TM) is a trademark of Fidelity National Information Services, Inc.
+   Other trademarks are the property of their respective owners.
 
    This document contains a description of GT.M and the operating
    instructions pertaining to the various functions that comprise the system.
@@ -7333,7 +7432,7 @@
 
    **Note**
 
-   This help file is a concise representation of revision V6.2-000 of the
+   This help file is a concise representation of revision V6.2-001 of the
    UNIX Administration and Operations Guide. To obtain a copy of the current
    revision, go to www.fis-gtm.com and then click on the User Documentation
    tab.
diff --git a/sr_port/mupip_cvtgbl.h b/sr_port/mupip_cvtgbl.h
index 9f4deb8..453ae07 100644
--- a/sr_port/mupip_cvtgbl.h
+++ b/sr_port/mupip_cvtgbl.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -13,5 +13,7 @@
 #define MUPIP_CVTGBL_INCLUDED
 
 void mupip_cvtgbl(void);
-
+#ifdef UNIX
+int get_file_format(char **line1_ptr, char **line2_ptr, int *line1_len, int *line2_len);
+#endif
 #endif /* MUPIP_CVTGBL_INCLUDED */
diff --git a/sr_port/mupip_reorg.c b/sr_port/mupip_reorg.c
index 227ffa8..9a71307 100644
--- a/sr_port/mupip_reorg.c
+++ b/sr_port/mupip_reorg.c
@@ -1,6 +1,6 @@
 /***************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -82,8 +82,6 @@ error_def(ERR_NOEXCLUDE);
 error_def(ERR_REORGCTRLY);
 error_def(ERR_REORGINC);
 
-GTMTRIG_ONLY(LITREF mval		literal_hasht;)
-
 GBLREF bool		mu_ctrlc_occurred;
 GBLREF bool		mu_ctrly_occurred;
 GBLREF boolean_t	mu_reorg_process;
@@ -297,19 +295,19 @@ void mupip_reorg(void)
 					if (truncate)
 					{	/* Reorg ^#t in this region to move it out of the way. */
 						SET_GVTARGET_TO_HASHT_GBL(cs_addrs);	/* sets gv_target */
+						inctn_opcode = inctn_invalid_op;	/* needed for INITIAL_HASHT_ROOT_SEARCH */
+						INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;	/* sets gv_target->root */
+						DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
 						hasht_gl.next = NULL;
 						hasht_gl.reg = gv_cur_region;
 						hasht_gl.gvt = gv_target;
-						inctn_opcode = inctn_invalid_op;	/* needed for *ROOT_SEARCH */
-						INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;	/* sets gv_target->root */
-						DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
 						if (0 != gv_target->root)
 						{
 							util_out_print("   ", FLUSH);
 							util_out_print("Global: !AD (region !AD)", FLUSH,
 								GNAME(&hasht_gl).len, GNAME(&hasht_gl).addr,
 								REG_LEN_STR(gv_cur_region));
-							reorg_gv_target->gvname.var_name = literal_hasht.str;
+							reorg_gv_target->gvname.var_name = gv_target->gvname.var_name;
 							cur_success = mu_reorg(&hasht_gl, &exclude_gl_head, &resume,
 										index_fill_factor, data_fill_factor, reorg_op);
 							reorg_success &= cur_success;
diff --git a/sr_port/mupip_set_journal_parse.c b/sr_port/mupip_set_journal_parse.c
index 58272c2..18008aa 100644
--- a/sr_port/mupip_set_journal_parse.c
+++ b/sr_port/mupip_set_journal_parse.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -91,7 +91,8 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
 			return FALSE;
 		if ((jnl_info->alloc < JNL_ALLOC_MIN) || (jnl_info->alloc > JNL_ALLOC_MAX))
 		{
-			gtm_putmsg(VARLSTCNT(5) ERR_JNLINVALLOC, 3, jnl_info->alloc, JNL_ALLOC_MIN, JNL_ALLOC_MAX);
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JNLINVALLOC, 3,
+						jnl_info->alloc, JNL_ALLOC_MIN, JNL_ALLOC_MAX);
 			return FALSE;
 		}
 	}
@@ -101,7 +102,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
 			return FALSE;
 		if (alignsize < JNL_MIN_ALIGNSIZE)
 		{
-			gtm_putmsg(VARLSTCNT(4) ERR_JNLMINALIGN, 2, alignsize, JNL_MIN_ALIGNSIZE);
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLMINALIGN, 2, alignsize, JNL_MIN_ALIGNSIZE);
 			return FALSE;
 		}
 		if (alignsize > JNL_MAX_ALIGNSIZE)
@@ -109,11 +110,12 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
 			util_out_print("ALIGNSIZE cannot be greater than !UL", TRUE, JNL_MAX_ALIGNSIZE);
 			return FALSE;
 		}
-		LOG2_OF_INTEGER(alignsize, bits_of_alignsize);
+		assert(4 == SIZEOF(alignsize));	/* so we can use the 32bit version of ceil_log2 */
+		bits_of_alignsize = ceil_log2_32bit(alignsize);
 		if ((1 << bits_of_alignsize) != alignsize)
 		{
 			alignsize = 1 << bits_of_alignsize; /* This will make alignsize power of two */
-			gtm_putmsg(VARLSTCNT(3) ERR_JNLALIGNSZCHG, 1, alignsize);
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JNLALIGNSZCHG, 1, alignsize);
 		}
 		jnl_info->alignsize = alignsize * DISK_BLOCK_SIZE;
 	}
@@ -124,7 +126,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
 		if (JNL_AUTOSWITCHLIMIT_MIN > jnl_info->autoswitchlimit
 			|| JNL_ALLOC_MAX < jnl_info->autoswitchlimit)
 		{
-			gtm_putmsg(VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info->autoswitchlimit,
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info->autoswitchlimit,
 								JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX);
 			return FALSE;
 		}
@@ -163,7 +165,7 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info
 		}
 		if (jnl_info->extend > JNL_EXTEND_MAX)
 		{
-			gtm_putmsg(VARLSTCNT(4) ERR_JNLINVEXT, 2, jnl_info->extend, JNL_EXTEND_MAX);
+			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLINVEXT, 2, jnl_info->extend, JNL_EXTEND_MAX);
 			return FALSE;
 		}
 	}
diff --git a/sr_port/mv_stent.h b/sr_port/mv_stent.h
index cf1a26c..adb3e5b 100644
--- a/sr_port/mv_stent.h
+++ b/sr_port/mv_stent.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -91,6 +91,7 @@ typedef struct
 	mval			*ztvalue_save;		/* Save it once per trigger level */
 	mstr			*ztname_save;
 	mval			*ztdata_save;
+	mval			*ztdelim_save;
 	mval			*ztoldval_save;
 	mval			*ztriggerop_save;
 	mval			*ztupdate_save;
@@ -237,24 +238,24 @@ void push_stck(void* val, int val_size, void** addr, int mvst_stck_type);
 #define	MVST_LAST	18	/* update this, mvs_size and mvs_save in mtables.c, and switches in unw_mv_ent.c,
 				 * stp_gcol_src.h, and get_ret_targ.c when adding a new MVST type */
 
-/* Variation of ROUND_UP2 macro that doesn't have the checking that generates a GTMASSERT. This is necessary because the
- * MV_SIZE macro is used in a static table initializer so cannot have executable (non-constant) code in it
+/* Variation of ROUND_UP2 macro that doesn't have the checking that generates an assertpro. This is necessary because
+ * the MV_SIZE macro is used in a static table initializer so cannot have executable (non-constant) code in it
  */
 #define ROUND_UP2_NOCHECK(VALUE,MODULUS) (((VALUE) + ((MODULUS) - 1)) & ~((MODULUS) - 1))
 #define MV_SIZE(X) \
         ROUND_UP2_NOCHECK(((SIZEOF(*mv_chain) - SIZEOF(mv_chain->mv_st_cont) + SIZEOF(mv_chain->mv_st_cont.X))), NATIVE_WSIZE)
 
-#define PUSH_MV_STENT(T) (((msp -= mvs_size[T]) <= stackwarn) ?							\
-	((msp <= stacktop) ? (msp += mvs_size[T]/* fix stack */, rts_error(VARLSTCNT(1) ERR_STACKOFLOW)) :	\
-	 rts_error(VARLSTCNT(1) ERR_STACKCRIT)) :								\
-	(((mv_stent *)msp)->mv_st_type = T ,									\
-	((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)),				\
+#define PUSH_MV_STENT(T) (((msp -= mvs_size[T]) <= stackwarn) ?									\
+	((msp <= stacktop) ? (msp += mvs_size[T]/* fix stack */, rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW)) :	\
+	 rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT)) :								\
+	(((mv_stent *)msp)->mv_st_type = T ,											\
+	((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)),						\
 	mv_chain = (mv_stent *)msp)
 
 #define PUSH_MV_STCK(size, st_type) (((msp -= ROUND_UP(mvs_size[st_type] + (size), SIZEOF(char *))) <= stackwarn) ?	\
 	((msp <= stacktop) ? (msp += ROUND_UP(mvs_size[st_type] + (size), SIZEOF(char *)) /* fix stack */,		\
-        rts_error(VARLSTCNT(1) ERR_STACKOFLOW)) :									\
-	rts_error(VARLSTCNT(1) ERR_STACKCRIT)) :									\
+        rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW)) :							\
+	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT)) :							\
 	(((mv_stent *)msp)->mv_st_type = st_type,									\
 	((mv_stent *)msp)->mv_st_next = (int)((unsigned char *) mv_chain - msp)),					\
 	mv_chain = (mv_stent *)msp)
diff --git a/sr_port/obj_file.h b/sr_port/obj_file.h
index 33606c4..f0d5c24 100644
--- a/sr_port/obj_file.h
+++ b/sr_port/obj_file.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2009 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -14,21 +14,9 @@
 
 #include <obj_filesp.h>
 
-void emit_immed(char *source, uint4 size);
-void emit_literals(void);
-void emit_linkages(void);
-int literal_offset(UINTPTR_T offset);
-int4 find_linkage(mstr* name);
-void drop_object_file(void);
-UNIX_ONLY(void close_object_file(void);)
-VMS_ONLY(void close_object_file(rhdtyp *rhead);)
-void create_object_file(rhdtyp *rhead);
-void obj_init(void);
-DEBUG_ONLY(int output_symbol_size(void);)
-
 #define OUTPUT_SYMBOL_SIZE (SIZEOF(int4) + sym_table_size)
-
 #define PADCHARS	"PADDING PADDING"
+#define RENAME_TMP_OBJECT_FILE(FNAME) rename_tmp_object_file(FNAME)
 #ifndef SECTION_ALIGN_BOUNDARY
 #if defined(GTM64)
 #	define SECTION_ALIGN_BOUNDARY  16
@@ -37,7 +25,6 @@ DEBUG_ONLY(int output_symbol_size(void);)
 #endif /* GTM64 */
 #endif /* SECTION_ALIGN_BOUNDARY */
 #define OBJECT_SIZE_ALIGNMENT 16
-
 #ifdef DEBUG
 #define MAX_CODE_COUNT 10000
 /* This structure holds the size of the code generated for every triple */
@@ -48,4 +35,21 @@ struct inst_count
 };
 #endif /* DEBUG */
 
+/* Prototypes */
+#ifdef UNIX
+int mk_tmp_object_file(const char *object_fname, int object_fname_len);
+void rename_tmp_object_file(const char *object_fname);
+void init_object_file_name(void);
+void finish_object_file(void);
+#endif
+void emit_immed(char *source, uint4 size);
+void emit_literals(void);
+void emit_linkages(void);
+int literal_offset(UINTPTR_T offset);
+int4 find_linkage(mstr* name);
+void drop_object_file(void);
+void create_object_file(rhdtyp *rhead);
+void obj_init(void);
+VMS_ONLY(void close_object_file(rhdtyp *rhead);)
+DEBUG_ONLY(int output_symbol_size(void);)
 #endif /* OBJ_FILE_INCLUDED */
diff --git a/sr_port/objlabel.h b/sr_port/objlabel.h
index 18e0a25..84abe5f 100644
--- a/sr_port/objlabel.h
+++ b/sr_port/objlabel.h
@@ -33,7 +33,7 @@
  * Note that OBJ_UNIX_LABEL and OBJ_PLATFORM_LABEL should not exceed 255.
  */
 
-#define OBJ_UNIX_LABEL	28	/* When changed, be sure to zero the platform specific numbers below (if any non-0) */
+#define OBJ_UNIX_LABEL	29	/* When changed, be sure to zero the platform specific numbers below (if any non-0) */
 
 #if defined(__osf__)
 #	define	OBJ_PLATFORM_LABEL	0		/* Alpha/Tru64 */
diff --git a/sr_port/one_job_param.c b/sr_port/one_job_param.c
index 9bdf0be..8238828 100644
--- a/sr_port/one_job_param.c
+++ b/sr_port/one_job_param.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -43,9 +43,9 @@ const static readonly unsigned char job_param_index[27] =
 {
       /* A(2)    B(0)   C(2)   D(4)   E(2)   F(0)  G(2)  H(0)  I(4)   J(0)  K(0)  L(2)  M(0) */
 	 0,	2,    	 2,     4,     8,    10,     10,   12,   12,    16,   16,   16,   18,
-      /* N(6)	O(2)	P(4)	Q(0)	R(0)	S(6)	T(0)   U(0)	V(0)	W(0)   X(0)	Y(0)	Z(0) */
-	18,	24,	26,	30,	30,	30,	37,	37,	37,	37,	37,	37,	37,
-	37
+      /* N(6)	O(2)	P(6)	Q(0)	R(0)	S(6)	T(0)   U(0)	V(0)	W(0)   X(0)	Y(0)	Z(0) */
+	18,	24,	26,	32,	32,	32,	39,	39,	39,	39,	39,	39,	39,
+	39
 };
 #else
 const static readonly unsigned char job_param_index[27] =
diff --git a/sr_port/op_exp.c b/sr_port/op_exp.c
index 3ab2c46..0e41515 100644
--- a/sr_port/op_exp.c
+++ b/sr_port/op_exp.c
@@ -28,6 +28,7 @@ LITREF mval literal_zero;
 
 STATICFNDEF void op_exp_flgchk(mval *mv);
 
+error_def(ERR_DIVZERO);
 error_def(ERR_NEGFRACPWR);
 error_def(ERR_NUMOFLOW);
 
@@ -39,47 +40,38 @@ void op_exp(mval *u, mval* v, mval *p)
 	int		im0, im1, ie, i, j, j1;
 	boolean_t	fraction = FALSE, in = FALSE;
 	boolean_t	neg = FALSE, even = TRUE;
-	mval    	w, zmv;
-	int4    	n, n1;
+	mval		w, zmv;
+	int4		n, n1;
 	int4		z1_rnd, z2_rnd, pten;
 
 	u1_p = &u1;
 	memcpy(u1_p, u, SIZEOF(mval));
 	MV_FORCE_NUM(u1_p);
 	MV_FORCE_NUM(v);
-	if ((0 == v->m[1]) && (0 == v->m[0]))
-	{	/* 0**0 = 1 */
-		*p = literal_one;
-		return;
-	}
+	n = v->m[1];
 	if (0 != (v->mvtype & MV_INT))
 	{	/* Integer-ish exponent (could have up to 3 digits to right of decimal pt) */
-		n = v->m[1];
 		if (0 == n)
-		{	/* anything**0 = 1 where anything != 0 */
+		{	/* anything**0 = 1 */
 			*p = literal_one;
 			return;
 		}
 		if (0 != (u1_p->mvtype & MV_INT))
 		{	/* Integer-ish base */
 			if (0 == u1_p->m[1])
-			{	/* 0**anything = 0 */
-				*p = literal_zero;
-		                return;
+			{
+				if (0 <= n)
+				{	/* 0**anything non-negative = 0 */
+					*p = literal_zero;
+					return;
+				}
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DIVZERO);
 			}
-		} else if ((0 == u1_p->m[1]) && (0 == u1_p->m[0]))
-		{	/* 0**anything = 0 */
-			*p = literal_zero;
-			return;
-		}
+		} else
+			assert((0 != u1_p->m[1]) || (0 != u1_p->m[0]));
 		n1 = n / MV_BIAS;
 		if ((n1 * MV_BIAS) == n)
 		{	/* True non-fractional exponent */
-			if (0 == v->m[1])
-			{	/* Duplicate of check on line 58? */
-				*p = literal_one;
-				return;
-			}
 			if (0 > n1)
 			{	/* Create inverse due to negative exponent */
 				op_div((mval *)&literal_one, u1_p, &w);
@@ -102,7 +94,7 @@ void op_exp(mval *u, mval* v, mval *p)
 		{	/* Have non-integer exponent (has fractional component) */
 			if (0 != (u1_p->mvtype & MV_INT))
 			{	/* Base is integer-ish */
-                        	if (0 > u1_p->m[1])
+				if (0 > u1_p->m[1])
 				{	/* Base is negative, invalid exponent expression */
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NEGFRACPWR);
 					return;
@@ -115,31 +107,35 @@ void op_exp(mval *u, mval* v, mval *p)
 					return;
 				}
 			}
-                }
-        } else
+		}
+	} else
 	{	/* Exponent NOT integer-ish */
-	        if (0 != (u1_p->mvtype & MV_INT))
-        	{	/* Base is integer-ish */
-                	if (0 > u1_p->m[1])
-                	{	/* Base is negative - make positive but record was negative */
-                        	u1_p->m[1] = -u1_p->m[1];
-	                        neg = TRUE;
-        	        }
+		assert((0 != v->m[1]) || (0 != v->m[0]));
+		if (0 != (u1_p->mvtype & MV_INT))
+		{	/* Base is integer-ish */
 			if (0 == u1_p->m[1])
-			{	/* 0**anything is 0 */
-				*p = literal_zero;
-				return;
+			{
+				if (!v->sgn)
+				{	/* 0**anything non-negative = 0 */
+					*p = literal_zero;
+					return;
+				}
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DIVZERO);
 			}
-        	} else if (u1_p->sgn)
-        	{	/* Base is NOT integer-ish and is negative - clear sign and record with flag */
-                	u1_p->sgn = 0;
-	                neg = TRUE;
-			if ((0 == u1_p->m[1]) && (0 == u1_p->m[0]))
-			{	/* 0**anything is zero */
-				*p = literal_zero;
-				return;
+			if (0 > u1_p->m[1])
+			{	/* Base is negative - make positive but record was negative */
+				u1_p->m[1] = -u1_p->m[1];
+				neg = TRUE;
 			}
-        	}
+		} else
+		{	/* Base is NOT integer-ish */
+			assert((0 != u1_p->m[1]) || (0 != u1_p->m[0]));
+			if (u1_p->sgn)
+			{	/* and is negative - clear sign and record with flag */
+				u1_p->sgn = 0;
+				neg = TRUE;
+			}
+		}
 		if (NUM_DEC_DG_2L > (ie = (v->e - MV_XBIAS)))		/* Note assignment */
 		{	/* Need to determine 2 things:
 			 *   1. Whether this exponent has a fractional part (vs just being large)
@@ -208,7 +204,7 @@ void op_exp(mval *u, mval* v, mval *p)
 	if (HUGE_VAL == z)		/* Infinity return value check */
 	{
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NUMOFLOW);
-	        return;
+		return;
 	}
 #	endif
 	p->sgn = (neg && !even);	/* Positive numbers only from here on out */
@@ -252,14 +248,14 @@ void op_exp(mval *u, mval* v, mval *p)
 	 * Could add checks for zero/infinity here to avoid lengthy (300ish iterations) while loops below.
 	 */
 	n = 0;
-        while (1e16 <= z)
+	while (1e16 <= z)
 	{
-                n += 5;
+		n += 5;
 		z *= 1e-5;
 	}
-        while (1e1 > z)
+	while (1e1 > z)
 	{
-                n -= 5;
+		n -= 5;
 		z *= 1e5;
 	}
 	while (1e9 <= z)
diff --git a/sr_port/op_fntext.c b/sr_port/op_fntext.c
index 4874294..cba475c 100644
--- a/sr_port/op_fntext.c
+++ b/sr_port/op_fntext.c
@@ -20,14 +20,20 @@
 #include "op.h"
 #include "stringpool.h"
 #include "compiler.h"
+#include "min_max.h"
 #ifdef GTM_TRIGGER
 # include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
 #endif
 #include "stack_frame.h"
 
 GBLREF	spdesc		stringpool;
 GBLREF	stack_frame	*frame_pointer;
-GBLREF	uint4		dollar_tlevel;
+GTMTRIG_ONLY(GBLREF	uint4		dollar_tlevel);
+DBGTRIGR_ONLY(GBLREF	unsigned int	t_tries;)
 
 error_def(ERR_ZLINKFILE);
 error_def(ERR_ZLMODULE);
@@ -37,13 +43,14 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
 /* int_exp contains label offset or line number to reference */
 /* ret is used to return the correct string to caller */
 {
-	char		*cp;
-	int		i, lbl, letter;
-	mval		*temp_rtn, temp_mval;
-	mstr		*sld;
-	uint4		stat;
-	rhdtyp		*rtn_vector;
-	boolean_t	is_trigger, current_rtn = FALSE;
+	char			*cp;
+	int			i, lbl, letter;
+	mval			*temp_rtn, temp_mval;
+	mstr			*sld;
+	uint4			stat;
+	rhdtyp			*rtn_vector;
+	boolean_t		current_rtn = FALSE;
+	GTMTRIG_ONLY(boolean_t	is_trigger;)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -58,19 +65,20 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
 	sld = (mstr *)NULL;
 	ESTABLISH(fntext_ch);	/* to swallow errors and permit an emptystring result */
 	GTMTRIG_ONLY(IS_TRIGGER_RTN(&temp_rtn->str, is_trigger));
+	DBGIFTRIGR((stderr, "op_fntext: entering $tlevel=%d $t_tries=%d\n", dollar_tlevel, t_tries));
 	if ((0 == int_exp) && ((0 == label->str.len) || (0 == *label->str.addr)))
 		stat = ZEROLINE;
 	else
 	{
 #ifdef GTM_TRIGGER
+		DBGIFTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"));
 		if (is_trigger)
 		{
-			DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"));
 			assert(0 == TREF(op_fntext_tlevel));
 			TREF(op_fntext_tlevel) = 1 + dollar_tlevel;
 		}
 #endif
-		stat = get_src_line(temp_rtn, label, int_exp, &sld, VERIFY);
+		stat = get_src_line(temp_rtn, label, int_exp, &sld, &rtn_vector);
 		GTMTRIG_ONLY(TREF(op_fntext_tlevel) = 0);
 	}
 	if (0 == (stat & (CHECKSUMFAIL | NEGATIVELINE)))
@@ -128,5 +136,6 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
 		ret->str.addr = (char *)stringpool.free;
 		stringpool.free += ret->str.len;
 	}
+	DBGIFTRIGR((stderr, "op_fntext: exiting\n\n"));
 	return;
 }
diff --git a/sr_port/op_fnview.c b/sr_port/op_fnview.c
index 16d4c4a..ff34057 100644
--- a/sr_port/op_fnview.c
+++ b/sr_port/op_fnview.c
@@ -86,13 +86,15 @@ LITREF	mval		literal_zero;
 LITREF	mval		literal_one;
 LITREF	mval		literal_null;
 
-#define		MM_RES		"MM"
-#define		BG_RES		"BG"
-#define		CM_RES		"CM"
-#define		USR_RES		"USR"
-#define		GTM_BOOL_RES	"GT.M Boolean short-circuit"
-#define		STD_BOOL_RES	"Standard Boolean evaluation side effects"
-#define		WRN_BOOL_RES	"Standard Boolean with side-effect warning"
+#define		MM_RES			"MM"
+#define		BG_RES			"BG"
+#define		CM_RES			"CM"
+#define		USR_RES			"USR"
+#define		GTM_BOOL_RES		"GT.M Boolean short-circuit"
+#define		STD_BOOL_RES		"Standard Boolean evaluation side effects"
+#define		WRN_BOOL_RES		"Standard Boolean with side-effect warning"
+#define		STATS_MAX_DIGITS	MAX_DIGITS_IN_INT8
+#define		STATS_KEYWD_SIZE	(3 + 1 + 1)	/* 3 character mnemonic, colon and comma */
 
 STATICFNDCL unsigned char *gvn2gds(mval *gvn, gv_key *gvkey, int act);
 
@@ -110,6 +112,16 @@ STATICFNDCL unsigned char *gvn2gds(mval *gvn, gv_key *gvkey, int act);
 	stringpool.free += keylen;					\
 }
 
+#define STATS_PUT_PARM(TXT, CNTR, BASE)					\
+{									\
+	MEMCPY_LIT(stringpool.free, TXT);				\
+	stringpool.free += STR_LIT_LEN(TXT);				\
+	*stringpool.free++ = ':';					\
+	stringpool.free = i2ascl(stringpool.free, BASE.CNTR);		\
+	*stringpool.free++ = ',';					\
+	assert(stringpool.free <= stringpool.top);			\
+}
+
 void	op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
 {
 	VMS_ONLY(int	numarg;)
@@ -337,18 +349,42 @@ void	op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
 			s2pool(&tmpstr);
 			dst->str = tmpstr;
 			break;
-#ifdef		DEBUG
+		case VTK_POOLLIMIT:
+			assert(NULL != gd_header);	/* view_arg_convert would have done this for VTK_POOLLIMIT */
+			reg = parmblk.gv_ptr;
+			if (!reg->open)
+				gv_init_reg(reg);
+			csa = &FILE_INFO(reg)->s_addrs;
+			n = csa->gbuff_limit;
+			break;
 		case VTK_PROBECRIT:
-			if (!gd_header)
-				gvinit();
-			if (!parmblk.gv_ptr->open)
-				gv_init_reg(parmblk.gv_ptr);
+			assert(NULL != gd_header);	/* view_arg_convert would have done this for VTK_POOLLIMIT */
 			reg = parmblk.gv_ptr;
-			grab_crit(reg);
-			if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED))
-				rel_crit(reg);
+			if (!reg->open)
+				gv_init_reg(reg);
+			csa = &FILE_INFO(reg)->s_addrs;
+			if (NULL != csa->hdr)
+			{
+				UNIX_ONLY(csa->crit_probe = TRUE);
+				grab_crit(reg);
+				UNIX_ONLY(csa->crit_probe = FALSE);
+				if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED))
+					rel_crit(reg);
+				dst->str.len = 0;
+#				ifdef UNIX
+				ENSURE_STP_FREE_SPACE(n_probecrit_rec_types * (STATS_MAX_DIGITS + STATS_KEYWD_SIZE));
+				dst->str.addr = (char *)stringpool.free;
+				/* initialize csa->proberit_rec.p_crit_success field from cnl->gvstats_rec */
+				csa->probecrit_rec.p_crit_success = csa->nl->gvstats_rec.n_crit_success;
+#				define TAB_PROBECRIT_REC(CNTR,TEXT1,TEXT2)	STATS_PUT_PARM(TEXT1, CNTR, csa->probecrit_rec)
+#				include "tab_probecrit_rec.h"
+#				undef TAB_PROBECRIT_REC
+				assert(stringpool.free < stringpool.top);
+				/* subtract one to remove extra trailing comma delimiter */
+				dst->str.len = INTCAST((char *)stringpool.free - dst->str.addr - 1);
+#				endif
+			}
 			break;
-#endif
 		case VTK_REGION:
 			gblnamestr = &parmblk.str;
 			assert(NULL != gd_header); /* "view_arg_convert" call done above would have set this (for VTP_DBKEY case) */
@@ -450,23 +486,11 @@ void	op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
 			csa = &FILE_INFO(parmblk.gv_ptr)->s_addrs;
 			if (NULL != csa->hdr)
 			{
-#				define GVSTATS_MAX_DIGITS	MAX_DIGITS_IN_INT8
-#				define GVSTATS_KEYWORD_SIZE	5		/* THREE PLUS TWO DELIMITERS */
-#				define GVSTATS_KEYWORD_COUNT	n_gvstats_rec_types
-#				define GVSTATS_MAX_SIZE (GVSTATS_KEYWORD_COUNT * (GVSTATS_MAX_DIGITS + GVSTATS_KEYWORD_SIZE))
-				ENSURE_STP_FREE_SPACE(GVSTATS_MAX_SIZE);
+				ENSURE_STP_FREE_SPACE(n_gvstats_rec_types * (STATS_MAX_DIGITS + STATS_KEYWD_SIZE));
 				dst->str.addr = (char *)stringpool.free;
 				/* initialize cnl->gvstats_rec.db_curr_tn field from file header */
 				csa->nl->gvstats_rec.db_curr_tn = csa->hdr->trans_hist.curr_tn;
-#				define GVSTATS_PUT_PARM(TXT, CNTR, cnl)						\
-				{										\
-					MEMCPY_LIT(stringpool.free, TXT);					\
-					stringpool.free += STR_LIT_LEN(TXT);					\
-					*stringpool.free++ = ':';						\
-					stringpool.free = i2ascl(stringpool.free, cnl->gvstats_rec.CNTR);	\
-					*stringpool.free++ = ',';						\
-				}
-#				define TAB_GVSTATS_REC(COUNTER,TEXT1,TEXT2)	GVSTATS_PUT_PARM(TEXT1, COUNTER, csa->nl)
+#				define TAB_GVSTATS_REC(CNTR,TEXT1,TEXT2)	STATS_PUT_PARM(TEXT1, CNTR, csa->nl->gvstats_rec)
 #				include "tab_gvstats_rec.h"
 #				undef TAB_GVSTATS_REC
 				assert(stringpool.free < stringpool.top);
diff --git a/sr_port/op_fnztrigger.c b/sr_port/op_fnztrigger.c
index 9347884..d9efb4d 100644
--- a/sr_port/op_fnztrigger.c
+++ b/sr_port/op_fnztrigger.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -142,7 +142,7 @@ CONDITION_HANDLER(op_fnztrigger_ch)
 void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst)
 {
 	int				inparm_len, index;
-	uint4				dummy_stats[NUM_STATS], filename_len;
+	uint4				filename_len;
 	boolean_t			failed;
 	char				filename[MAX_FN_LEN + 1];
 	DCL_THREADGBL_ACCESS;
@@ -211,25 +211,25 @@ void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst)
 	switch(ztrprm_data[index])
 	{
 		case ZTRP_FILE:
-			if (0 == arg1->str.len)
-				/* 2nd parameter is missing */
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2);
-			if (MAX_FN_LEN < arg1->str.len)
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FILENAMETOOLONG);
-			/* The file name is in string pool so make a local copy in case GC happens */
-			strncpy(filename, arg1->str.addr, arg1->str.len);
-			filename_len = arg1->str.len;
-			filename[filename_len] = '\0';
-			failed = trigger_trgfile_tpwrap(filename, filename_len, TRUE);
+			/* If 2nd parameter is empty, do nothing (but dont issue error) */
+			if (arg1->str.len)
+			{
+				if (MAX_FN_LEN < arg1->str.len)
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FILENAMETOOLONG);
+				/* The file name is in string pool so make a local copy in case GC happens */
+				strncpy(filename, arg1->str.addr, arg1->str.len);
+				filename_len = arg1->str.len;
+				filename[filename_len] = '\0';
+				failed = trigger_trgfile_tpwrap(filename, filename_len, TRUE);
+			} else
+				failed = FALSE;
 			break;
 		case ZTRP_ITEM:
-			if (0 == arg1->str.len)
-				/* 2nd parameter is missing */
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ZTRIGINVACT, 1, 2);
-			failed = trigger_update(arg1->str.addr, arg1->str.len);
+			/* If 2nd parameter is empty, do nothing (but dont issue error) */
+			failed = (arg1->str.len) ? trigger_update(arg1->str.addr, arg1->str.len) : FALSE;
 			break;
 		case ZTRP_SELECT:
-			failed = (TRIG_FAILURE == trigger_select(arg1->str.addr, arg1->str.len, NULL, 0));
+			failed = trigger_select_tpwrap(arg1->str.addr, arg1->str.len, NULL, 0);
 			break;
 		default:
 			assertpro(FALSE && ztrprm_data[index]);	/* Should never happen with checks above */
diff --git a/sr_port/op_hang.c b/sr_port/op_hang.c
index 28ace8f..8304def 100644
--- a/sr_port/op_hang.c
+++ b/sr_port/op_hang.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -60,6 +60,10 @@
 #ifdef DEBUG
 #include "have_crit.h"		/* for the TPNOTACID_CHECK macro */
 #endif
+#ifdef UNIX
+#include "sleep.h"
+#include "time.h"
+#endif
 
 GBLREF	uint4		dollar_trestart;
 GBLREF	mv_stent	*mv_chain;
@@ -176,7 +180,10 @@ void op_hang(mval* num)
 				return;		/* done HANGing */
 		}
 #		ifdef UNIX
-		hiber_start(ms);
+		if (ms < 10)
+			SLEEP_USEC(ms * 1000, TRUE);	/* Finish the sleep if it is less than 10ms. */
+		else
+			hiber_start(ms);
 #		elif defined(VMS)
 		time[0] = -time_low_ms(ms);
 		time[1] = -time_high_ms(ms) - 1;
diff --git a/sr_port/op_indpat.c b/sr_port/op_indpat.c
index d01b8f2..63fe8a0 100644
--- a/sr_port/op_indpat.c
+++ b/sr_port/op_indpat.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -19,7 +19,7 @@
 #include "compile_pattern.h"
 #include "op.h"
 
-GBLREF short int 		source_column;
+GBLREF int	source_column;
 
 void	op_indpat(mval *v, mval *dst)
 {
diff --git a/sr_port/op_indtext.c b/sr_port/op_indtext.c
index 4533996..57f0356 100644
--- a/sr_port/op_indtext.c
+++ b/sr_port/op_indtext.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -29,7 +29,7 @@
 #include "stack_frame.h"
 
 GBLREF unsigned char 		*source_buffer;
-GBLREF short int 		source_column;
+GBLREF int	 		source_column;
 GBLREF spdesc 			stringpool;
 GBLREF mv_stent			*mv_chain;
 GBLREF unsigned char		*msp, *stackwarn, *stacktop;
diff --git a/sr_port/op_lvpatwrite.c b/sr_port/op_lvpatwrite.c
index ff0440a..379172e 100644
--- a/sr_port/op_lvpatwrite.c
+++ b/sr_port/op_lvpatwrite.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -48,7 +48,6 @@ void op_lvpatwrite(UNIX_ONLY_COMMA(int4 count) UINTPTR_T arg1, ...)
 	MAXSTR_BUFF_DECL(buff);
 
 	SETUP_THREADGBL_ACCESS;
-	TREF(in_zwrite) = TRUE;
 	VAR_START(var, arg1);
 	VMS_ONLY(va_count(count));
 	assert(1 < count);
@@ -115,7 +114,7 @@ void op_lvpatwrite(UNIX_ONLY_COMMA(int4 count) UINTPTR_T arg1, ...)
 				lvzwr_arg(flag, (mval *)arg1, (mval *)0);
 				break;
 			default:
-				GTMASSERT;
+				assertpro(FALSE);
 				break;
 		}
 	}
diff --git a/sr_port/op_lvzwrite.c b/sr_port/op_lvzwrite.c
index 26d6390..ef55cd9 100644
--- a/sr_port/op_lvzwrite.c
+++ b/sr_port/op_lvzwrite.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -48,7 +48,6 @@ void op_lvzwrite(UNIX_ONLY_COMMA(int4 count) long arg1, ...)
 	MAXSTR_BUFF_DECL(buff);
 
 	SETUP_THREADGBL_ACCESS;
-	TREF(in_zwrite) = TRUE;
 	VAR_START(var, arg1);
 	VMS_ONLY(va_count(count));
 	MAXSTR_BUFF_INIT;
@@ -105,7 +104,7 @@ void op_lvzwrite(UNIX_ONLY_COMMA(int4 count) long arg1, ...)
 				lvzwr_arg(flag, (mval *)arg1, (mval *)0);
 				break;
 			default:
-				GTMASSERT;
+				assertpro(FALSE);
 				break;
 		}
 	}
diff --git a/sr_port/op_merge.c b/sr_port/op_merge.c
index 845dcf1..048e421 100644
--- a/sr_port/op_merge.c
+++ b/sr_port/op_merge.c
@@ -469,6 +469,7 @@ void op_merge(void)
 				lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
 				lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
 				lvzwr_var(mglvnp->lclp[IND2], 0);
+				TREF(in_zwrite) = FALSE;
 #				ifdef DEBUG
 				/* assert that destination got all data of the source and its descendants */
 				op_fndata(mglvnp->lclp[IND2], value);
@@ -495,6 +496,7 @@ void op_merge(void)
 				lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v);
 				lvzwr_arg(ZWRITE_ASTERISK, 0, 0);
 				lvzwr_var(mglvnp->lclp[IND2], 0);
+				TREF(in_zwrite) = FALSE;
 				gvname_env_restore(gblp1);	 /* store destination as naked indicator in gv_currkey */
 			}
 		}
diff --git a/sr_port/op_rhdaddr.c b/sr_port/op_rhdaddr.c
index c008eef..9199162 100644
--- a/sr_port/op_rhdaddr.c
+++ b/sr_port/op_rhdaddr.c
@@ -19,7 +19,7 @@
 GBLREF mident_fixed	zlink_mname;
 GBLREF rtn_tabent	*rtn_names;
 
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 LITDEF mval		literal_null;
 #endif
 
@@ -29,7 +29,7 @@ error_def(ERR_ZLMODULE);
 /* For routine name given, return routine header address if rhd not already set */
 rhdtyp	*op_rhdaddr(mval *name, rhdtyp *rhd)
 {
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
 	return op_rhd_ext(name, (mval *)&literal_null, rhd, NULL);
 #	else
 	return (NULL != rhd) ? rhd : op_rhdaddr1(name);
@@ -64,7 +64,7 @@ rhdtyp	*op_rhdaddr1(mval *name)
 				ERR_ZLMODULE, 2, strlen(&zlink_mname.c[0]), zlink_mname.c);
 #		endif
 	}
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
 	/* In this (autorelink) context, no need to pass 4th arg (*lnr) since other opcodes used in conjunction with
 	 * op_rhdaddr1 will handle label offset if necessary.
 	 */
diff --git a/sr_port/op_setzbrk.c b/sr_port/op_setzbrk.c
index 7720e3e..aa6cf1f 100644
--- a/sr_port/op_setzbrk.c
+++ b/sr_port/op_setzbrk.c
@@ -30,9 +30,14 @@
 #include "gtm_text_alloc.h"
 #include "srcline.h"
 #include "compiler.h"
+#include "min_max.h"
 #ifdef GTM_TRIGGER
 # include "trigger_source_read_andor_verify.h"
 # include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
 #endif
 
 GBLREF z_records		zbrk_recs;
@@ -57,7 +62,7 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	char		*cp, zbloc_buff[MAX_ENTRYREF_LEN], *zbloc_end;
 	mident		*lab_name, *dummy;
 	mident		rname, lname;
-	mstr		*obj;
+	mstr		*obj, tmprtnname;
 	rhdtyp		*routine;
 	zb_code		*addr, tmp_xf_code;
 	int4		*line_offset_addr, *next_line_offset_addr;
@@ -67,7 +72,8 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	uint4		status;
 	int		sstatus;
 	icode_str	indir_src;
-	boolean_t	deleted, is_trigger;
+	boolean_t	deleted;
+	GTMTRIG_ONLY(boolean_t	is_trigger);
 
 	MV_FORCE_STR(rtn);
 	MV_FORCE_STR(lab);
@@ -83,18 +89,26 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	else
 	{
 		GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
-		GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n")));
+		DBGIFTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n"));
 		flush_pio();
 		if (WANT_CURRENT_RTN(rtn))
 			routine = CURRENT_RHEAD_ADR(frame_pointer->rvector);
 		else if (NULL == (routine = find_rtn_hdr(&rtn->str)))	/* Note assignment */
 		{
 #			ifdef GTM_TRIGGER
+			/* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+			 * region-name specification (the string component is unmodified). Pass in a copy of the mstr
+			 * struct to avoid modification to routine->str as it affects the caller which relies on this
+			 * variable being untouched.
+			 */
+			tmprtnname = rtn->str;
 			if (is_trigger)
 			{
-				sstatus = trigger_source_read_andor_verify(&rtn->str, TRIGGER_COMPILE);
-				if ((0 != sstatus) || (NULL == (routine = find_rtn_hdr(&rtn->str))))	/* Note assignment */
+				DEBUG_ONLY(routine = NULL;)
+				sstatus = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_COMPILE, &routine);
+				if (0 != sstatus)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+				assert(NULL != routine);
 			} else
 #			endif
 			{
@@ -108,26 +122,26 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 		lab_name = NULL;
 		if (NULL == (line_offset_addr = find_line_addr(routine, &lab->str, offset, &lab_name)))
 			dec_err(VARLSTCNT(1) ERR_NOPLACE);
-		else if (CANCEL_ONE == cnt)		/* cancel zbreak */
+		else if (CANCEL_ONE == cnt)	/* Cancel ZBREAK */
 		{
 			addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
 			addr = find_line_call(addr);
 			if (NULL != (z_ptr = zr_find(&zbrk_recs, addr)))
-				zr_put_free(&zbrk_recs, z_ptr);
+				zr_remove_zbreak(&zbrk_recs, z_ptr);
 			else
 				dec_err(VARLSTCNT(1) ERR_NOZBRK);
-		} else if (0 <= cnt)		/* set zbreak */
+		} else if (0 <= cnt)		/* Set ZBREAK */
 		{
 #			ifdef ZB_AT_COMMENT_INFO
 			dummy = NULL;
 			next_line_offset_addr = find_line_addr(routine, &lab->str, offset + 1, &dummy);
 			if (NULL != next_line_offset_addr && *next_line_offset_addr == *line_offset_addr)
-			{ /* we don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
+			{ 	/* We don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
 				dec_err(VARLSTCNT(1) ERR_COMMENT);
 				assert(lab_name == dummy);
 			}
 #			endif
-			op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
+			op_commarg(act, indir_linetail); 	/* This puts entry in stack and also increments refcnt field */
 			indir_src.str = act->str;
 			indir_src.code = indir_linetail;
 			obj = cache_get(&indir_src);
@@ -146,14 +160,14 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 			{
 #				ifdef USHBIN_SUPPORTED
 				if ((NULL != routine->shared_ptext_adr) && (routine->shared_ptext_adr == routine->ptext_adr))
-				{	/* setting a breakpoint in a shared routine, need to make a private copy */
+				{	/* Setting a breakpoint in a shared routine, need to make a private copy */
 					addr_off = (unsigned char *)addr - routine->ptext_adr;
 					if (SS_NORMAL == (status = cre_private_code_copy(routine)))
 						addr = (zb_code *)(routine->ptext_adr + addr_off);
 					else
 					{
 						assert(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY) == status);
-						/* convert to label+offset^routine to be presented to the user */
+						/* Convert to label+offset^routine to be presented to the user */
 						rname.len = rtn->str.len;
 						rname.addr = rtn->str.addr;
 						lname.len = lab->str.len;
@@ -164,15 +178,21 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 					}
 				}
 #				endif
-				z_ptr = zr_get_free(&zbrk_recs, addr);
+				z_ptr = zr_add_zbreak(&zbrk_recs, addr);
 				NON_USHBIN_ONLY(fix_pages((unsigned char *)addr, (unsigned char *)addr));
-
-				/* save for later restore while cancelling breakpoint */
+				/* Modify the instruction at the ZBREAK site. See zbreaksp.h for description of how this works
+				 * on a given platform.
+				 *
+				 * Save original instruction for later restore when cancelling this breakpoint.
+				 */
 #				ifdef	COMPLEX_INSTRUCTION_UPDATE
 				EXTRACT_OFFSET_TO_M_OPCODE(z_ptr->m_opcode, addr);
 #				else
-				z_ptr->m_opcode = *addr; /* save for later restore while cancelling breakpoint */
+				z_ptr->m_opcode = *addr;
 #				endif
+				/* Modify op_linestart or op_linefetch transfer table reference instruction to the appropriate
+				 * ZBREAK related flavor of instruction instead.
+				 */
 				tmp_xf_code = (z_ptr->m_opcode & ZB_CODE_MASK) >> ZB_CODE_SHIFT;
 				if (xf_linefetch * SIZEOF(UINTPTR_T) == tmp_xf_code)
 				{
@@ -194,18 +214,21 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 					assertpro( ((xf_zbstart * SIZEOF(UINTPTR_T)) == tmp_xf_code)
 						|| ((xf_zbfetch * SIZEOF(UINTPTR_T)) == tmp_xf_code));
 				z_ptr->rtn = &(CURRENT_RHEAD_ADR(routine))->routine_name;
-				assert(lab_name != NULL);
+				assert(NULL != lab_name);
 				z_ptr->lab = lab_name;
 				z_ptr->offset = offset;
 				z_ptr->mpc = (zb_code *)((unsigned char *)addr - SIZEOF_LA);
+				z_ptr->rtnhdr = routine;
+				USHBIN_ONLY(routine->has_ZBREAK = TRUE);	/* USHBIN platforms know which rtns have ZBREAK */
 				inst_flush(addr, SIZEOF(INST_TYPE));
 			}
 			if (z_ptr->action)
-			{	/* A zbreak command was already set for this line */
-				/* Note when new action is same as old action, no resultant changes in zb_refcnt */
-				assert(z_ptr->action->zb_refcnt > 0);
+			{	/* A ZBREAK command was already set for this line. Note when new action is same as
+				 * old action, no resultant changes in zb_refcnt.
+				 */
+				assert(0 <z_ptr->action->zb_refcnt);
 				z_ptr->action->zb_refcnt--;
-				assert(z_ptr->action != csp || z_ptr->action->zb_refcnt > 0);
+				assert((z_ptr->action != csp) || (0 <z_ptr->action->zb_refcnt));
 			}
 			z_ptr->action = csp;
 			z_ptr->count = cnt;
diff --git a/sr_port/op_svget.c b/sr_port/op_svget.c
index 15f1544..b2b022a 100644
--- a/sr_port/op_svget.c
+++ b/sr_port/op_svget.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -36,6 +36,7 @@
 #include "op.h"
 #include "mvalconv.h"
 #include "zroutines.h"
+#include "zshow.h"
 #include "getstorage.h"
 #include "get_command_line.h"
 #include "getzposition.h"
@@ -98,6 +99,7 @@ GBLREF boolean_t	dollar_zquit_anyway;
 #ifdef GTM_TRIGGER
 GBLREF	mstr		*dollar_ztname;
 GBLREF	mval		*dollar_ztdata;
+GBLREF	mval		*dollar_ztdelim;
 GBLREF	mval		*dollar_ztoldval;
 GBLREF	mval		*dollar_ztriggerop;
 GBLREF	mval		dollar_ztslate;
@@ -453,6 +455,17 @@ void op_svget(int varnum, mval *v)
 #			else
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
 #			endif
+		case SV_ZTDELIM:
+#			ifdef GTM_TRIGGER
+			assert(!dollar_ztdelim || MV_DEFINED(dollar_ztdelim));
+			if (NULL == dollar_ztdelim || !(MV_STR & dollar_ztdelim->mvtype) || (0 == dollar_ztdelim->str.len))
+				memcpy(v, &literal_null, SIZEOF(mval));
+			else
+				memcpy(v, dollar_ztdelim, SIZEOF(mval));
+			break;
+#			else
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
+#			endif
 		case SV_ZTOLDVAL:
 #			ifdef GTM_TRIGGER
 			/* Value comes from GT.M, but it might be numeric and need conversion to a string */
diff --git a/sr_port/op_tcommit.c b/sr_port/op_tcommit.c
index aa1d546..8f564ea 100644
--- a/sr_port/op_tcommit.c
+++ b/sr_port/op_tcommit.c
@@ -473,7 +473,7 @@ enum cdb_sc	op_tcommit(void)
 				GTMTRIG_ONLY(DBGTRIGR((stderr, "op_tcommit: Return status = %d\n", status));)
 				return status;	/* return status to caller who cares about it */
 			}
-			assert(UNIX_ONLY(jgbl.onlnrlbk ||) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+			assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
 			csa = jnl_fence_ctl.fence_list;
 			if ((JNL_FENCE_LIST_END != csa) && jgbl.wait_for_jnl_hard && !is_updproc && !mupip_jnl_recover)
 			{	/* For mupip journal recover all transactions applied during forward phase are treated as
@@ -498,7 +498,7 @@ enum cdb_sc	op_tcommit(void)
 				rel_crit(tr->reg);
 			}
 		}
-		assert(UNIX_ONLY(jgbl.onlnrlbk ||) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+		assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
 		/* Commit was successful */
 		dollar_trestart = 0;
 		t_tries = 0;
diff --git a/sr_port/op_tstart.c b/sr_port/op_tstart.c
index 337fc61..aca4604 100644
--- a/sr_port/op_tstart.c
+++ b/sr_port/op_tstart.c
@@ -215,9 +215,9 @@ void	op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
 			t_tries = (FALSE == mupip_jnl_recover) ? 0 : CDB_STAGNATE;
 			t_fail_hist[t_tries] = cdb_sc_normal;
 			/* ensure that we don't have crit on any region at the beginning of a TP transaction (be it GT.M or MUPIP).
-			 * The only exception is ONLINE ROLLBACK which holds crit for the entire duration
+			 * The only exception is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
 			 */
-			assert(0 == have_crit(CRIT_HAVE_ANY_REG) UNIX_ONLY(|| jgbl.onlnrlbk));
+			assert(0 == have_crit(CRIT_HAVE_ANY_REG) UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
 		}
 #		ifdef GTM_TRIGGER
 		else
@@ -403,10 +403,16 @@ void	op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
 	tf->restartable = (NORESTART != prescnt);
 	tf->old_locks = (NULL != mlk_pvt_root);
 #	ifdef DEBUG
-	if (!jgbl.forw_phase_recovery)
-	{	/* In case of forward phase of journal recovery, gv_currkey is set by caller (mur_forward) only
-		 * after the call to op_tstart so avoid doing gv_currkey check.
-		 */
+	/* Do check that gv_currkey and gv_target are in sync.
+	 * In case of forward phase of journal recovery, gv_currkey is set by caller (mur_forward) only
+	 * after the call to op_tstart so avoid doing gv_currkey check. Also in case of trigger_upgrade,
+	 * we could start a TP transaction from almost anywhere (e.g. inside name-level $order in op_gvorder)
+	 * and so we are not guaranteed this check will succeed. Since this check is not necessary anymore
+	 * (see comment before macro definition) we skip this check in that case. A broad (but not accurate)
+	 * way to check for trigger_upgrade is if gv_target is directory-tree (i.e. gvname is "").
+	 */
+	if (!jgbl.forw_phase_recovery && (NULL != gv_target) && gv_target->gvname.var_name.len)
+	{
 		DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
 	}
 #	endif
@@ -599,6 +605,7 @@ void	op_tstart(int implicit_flag, ...) /* value of $T when TSTART */
 		assert((NULL != first_ua) && (NULL != curr_ua)); /* Since first_sgm_info is NOT NULL, database activity existed */
 		new_gtli->curr_ua = (struct ua_list *)(curr_ua);
 		new_gtli->upd_array_ptr = update_array_ptr;
+		GTMTRIG_ONLY(new_gtli->ztrigbuffLen = TREF(ztrigbuffLen);)
 		new_gtli->next_global_tlvl_info = NULL;
 		if (prev_gtli)
 		{
diff --git a/sr_port/op_unwind.c b/sr_port/op_unwind.c
index fde72e1..09d7b8c 100644
--- a/sr_port/op_unwind.c
+++ b/sr_port/op_unwind.c
@@ -33,6 +33,7 @@
 #include "gdsbt.h"
 #include "gdsfhead.h"
 #include "alias.h"
+#include "zr_unlink_rtn.h"
 #ifdef GTM_TRIGGER
 # include "gtm_trigger_trc.h"
 #endif
@@ -59,7 +60,9 @@ error_def(ERR_TPQUIT);
 /* This has to be maintained in parallel with unw_retarg(), the unwind with a return argument (extrinisic quit) routine. */
 void op_unwind(void)
 {
+	rhdtyp			*rtnhdr;
 	mv_stent 		*mvc;
+	stack_frame		*fp;
 	DBGEHND_ONLY(stack_frame *prevfp;)
 	DCL_THREADGBL_ACCESS;
 
@@ -116,6 +119,7 @@ void op_unwind(void)
 #	endif
 	DRAIN_GLVN_POOL_IF_NEEDED;
 	PARM_ACT_UNSTACK_IF_NEEDED;
+	USHBIN_ONLY(rtnhdr = frame_pointer->rvector);	/* Save rtnhdr for cleanup call below */
 	frame_pointer = frame_pointer->old_frame_pointer;
 	DBGEHND((stderr, "op_unwind: Stack frame 0x"lvaddr" unwound - frame 0x"lvaddr" now current - New msp: 0x"lvaddr"\n",
 		 prevfp, frame_pointer, msp));
@@ -128,6 +132,7 @@ void op_unwind(void)
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO);
 		assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
 	}
+	USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(rtnhdr));
 	/* We just unwound a frame. May have been either a zintrupt frame and/or may have unwound a NEW'd ZTRAP or even cleared
 	 * our error state. If we have a deferred timeout and none of the deferral conditions are anymore in effect, release
 	 * the hounds.
diff --git a/sr_port/op_view.c b/sr_port/op_view.c
index f6dc9c3..78a5f33 100644
--- a/sr_port/op_view.c
+++ b/sr_port/op_view.c
@@ -69,12 +69,12 @@
 #  include "gtmsecshr.h"
 # endif
 #endif
-#if defined(DEBUG) && defined(USHBIN_SUPPORTED)
+#ifdef AUTORELINK__SUPPORTED
 # include "relinkctl.h"
 #endif
 #include "gtmimagename.h"
 
-STATICFNDCL void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg);
+STATICFNDCL void view_dbop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg);
 
 GBLREF	volatile int4 		db_fsync_in_prog;
 GBLREF	boolean_t		certify_all_blocks;
@@ -144,54 +144,50 @@ error_def(ERR_ZDEFACTIVE);
 
 void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 {
-	int4			testvalue, tmpzdefbufsiz;
-	uint4			jnl_status, dummy_errno;
-	int			status, lcnt, icnt, recnum;
-	gd_region		*reg, *r_top, *save_reg;
-	gv_namehead		*gvnh;
-	mval			*arg, *nextarg, outval;
-	mstr			tmpstr;
-	va_list			var;
-	viewparm		parmblk, parmblk2;
-	viewtab_entry		*vtp;
+	boolean_t		dbgdmpenabled, was_crit, was_skip_gtm_putmsg;
+	char			*chptr;
+	collseq			*new_lcl_collseq;
 	gd_addr			*addr_ptr;
+	gd_region		*reg, *r_top, *save_reg;
 	gvnh_reg_t		*gvnh_reg;
 	gvnh_spanreg_t		*gvspan;
+	gv_namehead		*gvnh;
+	hash_table_mname	*table;
+	ht_ent_mname		*tabent, *table_base_orig, *topent;
+	int			clrlen, lcnt, lct, icnt, ncol, nct, status, table_size_orig;
+	int4			testvalue, tmpzdefbufsiz;
+	jnl_buffer_ptr_t	jb;
+	lv_blk			*lvbp;
+	lv_val			*lv, *lvp, *lvp_top;
+	mstr			tmpstr;
+	mval			*arg, *nextarg, outval;
 	noisolation_element	*gvnh_entry;
-	int			lct, ncol, nct;
-	collseq			*new_lcl_collseq;
-	ht_ent_mname		*tabent, *topent;
-	lv_val			*lv;
-	symval			*cstab;
 	sgmnt_addrs		*csa;
 	sgmnt_data_ptr_t	csd;
-	jnl_buffer_ptr_t	jb;
-	int			table_size_orig;
-	ht_ent_mname		*table_base_orig;
-	hash_table_mname	*table;
-	boolean_t		dbgdmpenabled, was_crit, was_skip_gtm_putmsg;
-	symval			*lvlsymtab;
-	lv_blk			*lvbp;
-	lv_val			*lvp, *lvp_top;
-#	if defined(DEBUG) && defined(USHBIN_SUPPORTED)
+	symval			*cstab, *lvlsymtab;
+	uint4			jnl_status, dummy_errno;
+	va_list			var;
+	viewparm		parmblk, parmblk2;
+	viewtab_entry		*vtp;
+#	ifdef AUTORELINK_SUPPORTED
 	open_relinkctl_sgm	*linkctl;
 	relinkrec_t		*linkrec;
+	int			recnum;
 #	endif
 	VMS_ONLY(int		numarg;)
-
 	static readonly char msg1[] = "Caution: Database Block Certification Has Been ";
-	static readonly char msg2[] = "Disabled";
-	static readonly char msg3[] = "Enabled";
 	static readonly char lv_msg1[] =
 		"Caution: GT.M reserved local variable string pointer duplicate check diagnostic has been";
-	static readonly char upper[] = "UPPER";
+	static readonly char msg2[] = "Disabled";
+	static readonly char msg3[] = "Enabled";
 	static readonly char lower[] = "LOWER";
+	static readonly char upper[] = "UPPER";
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	VAR_START(var, keyword);
 	VMS_ONLY(va_count(numarg));
-		jnl_status = 0;
+	jnl_status = 0;
 	assertpro(1 <= numarg);
 	MV_FORCE_STR(keyword);
 	numarg--;	/* remove keyword from count */
@@ -232,13 +228,15 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 			outval.mvtype = MV_STR;
 			view_debug4 = (0 != MV_FORCE_INT(parmblk.value));
 			break;
+		case VTK_DBFLUSH:
 		case VTK_DBSYNC:
 		case VTK_EPOCH:
 		case VTK_FLUSH:
+		case VTK_GVSRESET:
 		case VTK_JNLFLUSH:
-		case VTK_DBFLUSH:
+		case VTK_POOLLIMIT:
 			arg = (numarg > 1) ? va_arg(var, mval *) : NULL;
-			view_dbflushop(vtp->keycode, &parmblk, arg);
+			view_dbop(vtp->keycode, &parmblk, arg);
 			break;
 #		ifdef UNIX
 		case VTK_DMTERM:
@@ -443,7 +441,8 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 			}
 			was_skip_gtm_putmsg = TREF(skip_gtm_putmsg);
 			TREF(skip_gtm_putmsg) = TRUE;	/* to avoid ready_collseq from doing gtm_putmsg in case of errors.
-							 * not doing so will cause GDECHECK errors in caller (GDE). */
+							 * not doing so will cause GDECHECK errors in caller (GDE).
+							 */
 			new_lcl_collseq = ready_collseq(lct);
 			TREF(skip_gtm_putmsg) = was_skip_gtm_putmsg;
 			if (0 == new_lcl_collseq)
@@ -619,9 +618,9 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 			tmpzdefbufsiz = MV_FORCE_INT(parmblk.value);
 			if (1 == tmpzdefbufsiz)
 				tmpzdefbufsiz = ZDEFDEF;
-			else  if (tmpzdefbufsiz < ZDEFMIN)
+			else if (tmpzdefbufsiz < ZDEFMIN)
 				tmpzdefbufsiz = ZDEFMIN;
-			else  if (tmpzdefbufsiz > ZDEFMAX)
+			else if (tmpzdefbufsiz > ZDEFMAX)
 				tmpzdefbufsiz = ZDEFMAX;
 			zdefbufsiz = (unsigned short)tmpzdefbufsiz;
 			break;
@@ -682,7 +681,8 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 			break;
 		case VTK_LVREHASH:
 			/* This doesn't actually expand or contract the local variable hash table but does cause it to be
-			 * rebuilt. Then we need to do the same sort of cleanup that add_hashtab_mname_symval does. */
+			 * rebuilt. Then we need to do the same sort of cleanup that add_hashtab_mname_symval does.
+			 */
 			/* Step 1: remember table we started with */
 			table = &curr_symval->h_symtab;
 			table_base_orig = table->base;
@@ -702,7 +702,7 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 		case VTK_STORDUMP:
 #			if defined(DEBUG) && defined(UNIX)
 			if (gtm_white_box_test_case_enabled
-			    && (WBTEST_HOLD_CRIT_TILL_LCKALERT == gtm_white_box_test_case_number))
+				&& (WBTEST_HOLD_CRIT_TILL_LCKALERT == gtm_white_box_test_case_number))
 			{	/* Hold crit for a long enough interval to generate lock alert which then does a continue_proc */
 				grab_crit(gv_cur_region);
 				icnt = TREF(continue_proc_cnt);
@@ -796,36 +796,15 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 			lv = (lv_val *)parmblk.value;
 			util_out_print("", RESET);	/* Reset the buffer */
 			util_out_print("LV: !AD  addr: 0x!XJ  mvtype: 0x!4XW  sign: !UB  exp: !UL  m[0]: !UL [0x!XL]  "
-				       "m[1]: !UL [0x!XL]  str.len: !UL  str.addr: 0x!XJ", SPRINT, arg->str.len, arg->str.addr,
-				       lv, lv->v.mvtype, lv->v.sgn, lv->v.e, lv->v.m[0], lv->v.m[0], lv->v.m[1], lv->v.m[1],
-				       lv->v.str.len, lv->v.str.addr);
+					"m[1]: !UL [0x!XL]  str.len: !UL  str.addr: 0x!XJ", SPRINT, arg->str.len, arg->str.addr,
+					lv, lv->v.mvtype, lv->v.sgn, lv->v.e, lv->v.m[0], lv->v.m[0], lv->v.m[1], lv->v.m[1],
+					lv->v.str.len, lv->v.str.addr);
 			outval.str.addr = TREF(util_outptr);
 			outval.str.len = STRLEN(TREF(util_outptr));
 			op_write(&outval);
 			op_wteol(1);
 			break;
 #		endif
-#		if defined(DEBUG) && defined(USHBIN_SUPPORTED)
-		case VTK_RCTLDUMP:
-			util_out_print("", RESET);	/* Reset output buffer */
-			for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
-			{
-				util_out_print_gtmio("relinkctl: 0x!XJ  entryname: !AD  records: !UL  hdr: 0x!XJ  base: 0x!XJ"
-						     "  locked: !UL", FLUSH, linkctl, linkctl->zro_entry_name.len,
-						     linkctl->zro_entry_name.addr, linkctl->n_records, linkctl->hdr,
-						     linkctl->rec_base, linkctl->locked);
-				util_out_print_gtmio("  hdr: records: !UL  nattached: !UL", FLUSH, linkctl->hdr->n_records,
-						     linkctl->hdr->nattached);
-				for (linkrec = linkctl->rec_base, recnum = 1; recnum <= linkctl->hdr->n_records;
-				     linkrec++, recnum++)
-				{
-					util_out_print_gtmio("    rec#!4UL: rtnname: !AD  cycle: !UL", FLUSH, recnum,
-							     mid_len(&linkrec->rtnname_fixed), &linkrec->rtnname_fixed.c,
-							     linkrec->cycle);
-				}
-			}
-			break;
-#		endif
 		default:
 			va_end(var);
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWCMD);
@@ -834,17 +813,16 @@ void	op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
 	return;
 }
 
-void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
+void view_dbop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
 {
-	uint4			jnl_status, dummy_errno;
-	int4			nbuffs;
-	int			save_errno;
-	int			status, lcnt, icnt;
+	boolean_t		was_crit;
 	gd_region		*reg, *r_top, *save_reg;
+	int			icnt, lcnt, save_errno, status;
+	int4			nbuffs;
+	jnl_buffer_ptr_t	jb;
 	sgmnt_addrs		*csa;
 	sgmnt_data_ptr_t	csd;
-	jnl_buffer_ptr_t	jb;
-	boolean_t		was_crit;
+	uint4			jnl_status, dummy_errno;
 	UNIX_ONLY(unix_db_info	*udi;)
 
 	if (NULL == gd_header)		/* open gbldir */
@@ -863,6 +841,14 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
 		gv_cur_region = reg;
 		switch(keycode)
 		{
+			case VTK_DBFLUSH:
+				if (!reg->read_only)
+				{
+					change_reg(); /* for jnl_ensure_open */
+					nbuffs = (NULL != thirdarg) ? MV_FORCE_INT(thirdarg) : cs_addrs->nl->wcs_active_lvl;
+					JNL_ENSURE_OPEN_WCS_WTSTART(cs_addrs, reg, nbuffs, dummy_errno);
+				}
+				break;
 			case VTK_DBSYNC:
 #				ifdef UNIX
 				if (!reg->read_only)
@@ -880,8 +866,8 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
 				}
 #				endif
 				break;
-			case VTK_FLUSH:
 			case VTK_EPOCH:
+			case VTK_FLUSH:
 				if (!reg->read_only)
 				{
 					change_reg(); /* for jnl_ensure_open */
@@ -896,6 +882,12 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
 					wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT | WCSFLU_SPEEDUP_NOBEFORE);
 				}
 				break;
+			case VTK_GVSRESET:
+				change_reg();
+				if (!reg->read_only)
+					CLRGVSTATS(cs_addrs);
+				memset((char *)&cs_addrs->gvstats_rec, 0, SIZEOF(gvstats_rec_t));	/* always process-private */
+				break;
 			case VTK_JNLFLUSH:
 				change_reg();
 				csa = cs_addrs;
@@ -932,13 +924,18 @@ void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
 						rel_crit(reg);
 				}
 				break;
-			case VTK_DBFLUSH:
-				if (!reg->read_only)
-				{
-					change_reg(); /* for jnl_ensure_open */
-					nbuffs = (NULL != thirdarg) ? MV_FORCE_INT(thirdarg) : cs_addrs->nl->wcs_active_lvl;
-					JNL_ENSURE_OPEN_WCS_WTSTART(cs_addrs, reg, nbuffs, dummy_errno);
-				}
+			case VTK_POOLLIMIT:
+				change_reg();
+				csa = cs_addrs;
+				csd = csa->hdr;
+				nbuffs = MV_FORCE_INT(thirdarg);
+				if ((MV_STR & thirdarg->mvtype) && ('%' == thirdarg->str.addr[thirdarg->str.len - 1]))
+					nbuffs = (100 == nbuffs) ? 0 : (csd->n_bts * nbuffs) / 100;		/* percentage */
+				csa->gbuff_limit = (0 == nbuffs) ? 0 : MAX(MIN(nbuffs, csd->n_bts * .5), MIN_GBUFF_LIMIT);
+				/* to pick the current "hand" as a pseudo-random spot for our area see dbg code in gvcst_init
+				 * but for the first release of this always pick the end of the buffer
+				 */
+				csa->our_midnite = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets + csd->n_bts;
 				break;
 		}
 	}
diff --git a/sr_port/op_zprint.c b/sr_port/op_zprint.c
index 187d627..044ca77 100644
--- a/sr_port/op_zprint.c
+++ b/sr_port/op_zprint.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -19,12 +19,19 @@
 #include "error.h"
 #include "op.h"
 #include "outofband.h"
+#include "min_max.h"
 #ifdef GTM_TRIGGER
 # include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
 #endif
 
 #define	INFO_MSK(error)	(error & ~SEV_MSK | INFO)
 
+DBGTRIGR_ONLY(GBLREF	uint4		dollar_tlevel;)
+DBGTRIGR_ONLY(GBLREF	unsigned int	t_tries;)
 GBLREF int4		outofband;
 GBLREF mident_fixed	zlink_mname;
 
@@ -43,67 +50,63 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
 /*	 parser makes the second label the duplicate	*/
 /*	 of the first. (not so vice versa)		*/
 {
-	mval		print_line, null_str;
-	mstr		*src1, *src2;
-	uint4		stat1, stat2;
-	rhdtyp		*rtn_vector;
-	boolean_t	is_trigger;
+	mval			print_line, null_str;
+	mstr			*src1, *src2;
+	uint4			stat1, stat2;
+	rhdtyp			*rtn_vector, *rtn_vector2;
+	GTMTRIG_ONLY(boolean_t	is_trigger;)
 
 	MV_FORCE_STR(start_label);
 	MV_FORCE_STR(end_label);
 	MV_FORCE_STR(rtn);
-	/* This first call to get_src_line() for our entry "locks-in" the source we will be extracting. If the rtn
-	 * in question in a trigger, it would be possible for the further get_src_line() calls we do to cause the
-	 * trigger to be reloaded making our earlier fetches irrelevant. After this first call, all following calls
-	 * to get_src_line() for this operation will tell get_src_line() to NOT verify or reload the triggers so
-	 * we get a consistent (if no longer current) view of the trigger.
-	 */
 	GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
-	GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_zprint: Performing zprint of a trigger\n")));
-	stat1 = get_src_line(rtn, start_label, start_int_exp, &src1, VERIFY);
+	DBGIFTRIGR((stderr, "op_zprint: Performing zprint of a trigger $tlevel=%d $trestart=%d\n", dollar_tlevel, t_tries));
+	stat1 = get_src_line(rtn, start_label, start_int_exp, &src1, &rtn_vector);
+	DBGIFTRIGR((stderr, "op_zprint: get_src_line returned %d\n", stat1));
 	if (OBJMODMISS == stat1)
 	{
 #		ifdef GTM_TRIGGER
 		if (is_trigger)
-			rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
 #		endif
 		/* get_src_line did not find the object file to load */
-		rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr,
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr,
 			  ERR_ZLMODULE, 2, mid_len(&zlink_mname), &zlink_mname.c[0]);
 	}
-	if (NULL == (rtn_vector = find_rtn_hdr(&rtn->str)))
-	{
-#		ifdef GTM_TRIGGER
-		if (is_trigger)
-			rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
-#		endif
-		GTMASSERT;	/* If couldn't find module, should have returned OBJMODMISS */
-	}
+	/* In case of GTM_TRIGGER, rtn_vector would have been initialized in the call to get_src_line above.
+	 * We need to use that and not do a find_rtn_hdr as rtn->str might contain region-name disambiguator
+	 * which find_rtn_hdr has no clue about. Even in case of no GTM_TRIGGER, we should be able to use rtn_vector
+	 * from "get_src_line". Assert that below before using.
+	 */
+	DEBUG_ONLY(NON_GTMTRIG_ONLY(rtn_vector2 = find_rtn_hdr(&rtn->str);))
+	NON_GTMTRIG_ONLY(assert(rtn_vector2 == rtn_vector);)
+	assertpro(NULL != rtn_vector);	/* If couldn't find module, should have returned OBJMODMISS */
 	if (stat1 & LABELNOTFOUND)
-		rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPRTLABNOTFND);
 	if (stat1 & SRCNOTFND)
-		rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, rtn_vector->src_full_name.len, rtn_vector->src_full_name.addr);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2,
+				rtn_vector->src_full_name.len, rtn_vector->src_full_name.addr);
 	if (stat1 & (SRCNOTAVAIL | AFTERLASTLINE))
 		return;
 	if (stat1 & (ZEROLINE | NEGATIVELINE))
 	{
 		null_str.mvtype = MV_STR;
 		null_str.str.len = 0;
-		stat1 = get_src_line(rtn, &null_str, 1, &src1, NOVERIFY);
+		stat1 = get_src_line(rtn, &null_str, 1, &src1, NULL);
 		if (stat1 & AFTERLASTLINE)		/* the "null" file */
 			return;
 	}
 	if (end_int_exp == 0 && (end_label->str.len == 0 || *end_label->str.addr == 0))
 		stat2 = AFTERLASTLINE;
-	else if ((stat2 = get_src_line(rtn, end_label, end_int_exp, &src2, NOVERIFY)) & LABELNOTFOUND)
-		rts_error(VARLSTCNT(1) ERR_ZPRTLABNOTFND);
+	else if ((stat2 = get_src_line(rtn, end_label, end_int_exp, &src2, NULL)) & LABELNOTFOUND)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPRTLABNOTFND);
 	if (stat2 & (ZEROLINE | NEGATIVELINE))
 		return;
 	if (stat2 & AFTERLASTLINE)
 	{
 		null_str.mvtype = MV_STR;
 		null_str.str.len = 0;
-		stat2 = get_src_line(rtn, &null_str, 1, &src2, NOVERIFY);
+		stat2 = get_src_line(rtn, &null_str, 1, &src2, NULL);
 		/* number of lines less one for duplicated zero'th line and one due
 		   to termination condition being <=
 		*/
@@ -112,13 +115,14 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
 	}
 	if (stat1 & CHECKSUMFAIL)
 	{
-		rts_error(VARLSTCNT(1) INFO_MSK(ERR_TXTSRCMAT));
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) INFO_MSK(ERR_TXTSRCMAT));
 		op_wteol(1);
 	}
 	print_line.mvtype = MV_STR;
+	DBGIFTRIGR((stderr, "op_zprint: printing the trigger from 0x%lx to 0x%lx\n", src1, src2));
 	for ( ; src1 <= src2 ; src1++)
 	{	/* Note outofband check currently disabled. This routine (op_zprint) needs to be rewritten to provide
-		 * a TP wrapper (if not already in place) and to buffer the lines obtained from get_src_line() completely
+		 * a TP wrapper (if not already in place) and to buffer the lines obtained from "get_src_line" completely
 		 * before outputting anything because obtaining these source lines is subject to TP restarts when we are
 		 * accessing triggers. In addition, for the case of "normal" routine source fetches, an outofband could
 		 * invoke a job interrupt which could relink an entry point so an out-of-band interrupt of any kind means
@@ -132,5 +136,6 @@ void op_zprint(mval *rtn, mval *start_label, int start_int_exp, mval *end_label,
 		op_write(&print_line);
 		op_wteol(1);
 	}
+	DBGIFTRIGR((stderr, "op_zprint: exiting\n\n"));
 	return;
 }
diff --git a/sr_port/op_zshow.c b/sr_port/op_zshow.c
index 5a37177..1e3f3af 100644
--- a/sr_port/op_zshow.c
+++ b/sr_port/op_zshow.c
@@ -36,6 +36,7 @@ void op_zshow(mval *func, int type, lv_val *lvn)
 {
 	const char	*ptr;
 	boolean_t	do_all = FALSE,
+			done_a = FALSE,
 			done_b = FALSE,
 			done_c = FALSE,
 			done_d = FALSE,
@@ -55,6 +56,8 @@ void op_zshow(mval *func, int type, lv_val *lvn)
 	{
 		switch (*ptr)
 		{
+			case 'A':
+			case 'a':
 			case 'B':
 			case 'b':
 			case 'C':
@@ -107,7 +110,16 @@ void op_zshow(mval *func, int type, lv_val *lvn)
 	{
 		output.line_num = 1;
 		switch (*ptr)
-		{	case 'B':
+		{
+			case 'A':
+			case 'a':
+				if (done_a)
+					break;
+				done_a = TRUE;
+				output.code = 'A';
+				ARLINK_ONLY(zshow_rctldump(&output));
+				break;
+			case 'B':
 			case 'b':
 				if (done_b)
 					break;
diff --git a/sr_port/opcode_def.h b/sr_port/opcode_def.h
index c8ee247..0ac2a6a 100644
--- a/sr_port/opcode_def.h
+++ b/sr_port/opcode_def.h
@@ -344,6 +344,8 @@ OPCODE_DEF(OC_STOLITC, (OCT_NULL))
 OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF))
 OPCODE_DEF(OC_FNZSOCKET, (OCT_MVAL | OCT_EXPRLEAF))
 OPCODE_DEF(OC_FNZSYSLOG, (OCT_MVAL | OCT_EXPRLEAF))
+#ifdef AUTORELINK_SUPPORTED
 OPCODE_DEF(OC_RHD_EXT, (OCT_CDADDR))
 OPCODE_DEF(OC_LAB_EXT, (OCT_CDADDR))
 OPCODE_DEF(OC_ZRUPDATE, (OCT_NULL))
+#endif
diff --git a/sr_port/put_indr.c b/sr_port/put_indr.c
index 5306aee..79a39b5 100644
--- a/sr_port/put_indr.c
+++ b/sr_port/put_indr.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -12,12 +12,11 @@
 #include "mdef.h"
 #include "compiler.h"
 
-oprtype put_indr(x)
-oprtype *x;
+oprtype put_indr(oprtype *x)
 {
-mval *p;
-oprtype a;
-a.oprclass = INDR_REF;
-a.oprval.indr = x;
-return a;
+	oprtype a;
+
+	a.oprclass = INDR_REF;
+	a.oprval.indr = x;
+	return a;
 }
diff --git a/sr_port/put_lit.c b/sr_port/put_lit.c
index 61b026e..c17ff25 100644
--- a/sr_port/put_lit.c
+++ b/sr_port/put_lit.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -35,10 +35,10 @@ oprtype put_lit(mval *x)
 	ref = newtriple(OC_LIT);
 	ref->operand[0].oprclass = MLIT_REF;
 	/* Multiple reasons to use hashtab since coerce which processes integer parms to functions will
-	   actually *remove* literals if they were just put on so we don't want to convert to hashtab
-	   then have that literal and/or some others yanked to pull us back under the count as that would
-	   confuse things mightily.
-	*/
+	 * actually *remove* literals if they were just put on so we don't want to convert to hashtab
+	 * then have that literal and/or some others yanked to pull us back under the count as that would
+	 * confuse things mightily.
+	 */
 	usehtab = (LIT_HASH_CUTOVER < mlitmax) || (complits_hashtab && complits_hashtab->base);
 	if (!usehtab)
 	{	/* Brute force scan under cutover .. should include all intrinsics */
diff --git a/sr_port/put_str.c b/sr_port/put_str.c
index 4ebff46..9b090d4 100644
--- a/sr_port/put_str.c
+++ b/sr_port/put_str.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2009 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -18,12 +18,13 @@
 
 GBLREF spdesc stringpool;
 
-oprtype put_str(char *pt,mstr_len_t n)
+oprtype put_str(char *pt, mstr_len_t n)
 {
 	mval p;
 
 	ENSURE_STP_FREE_SPACE(n);
 	memcpy(stringpool.free, pt, n);
+	memset(&p, 0, SIZEOF(mval));
 	p.mvtype = MV_STR;
 	p.str.len = n;
 	p.str.addr = (char *) stringpool.free;
diff --git a/sr_port/repl_errno.h b/sr_port/repl_errno.h
index e3a4aaa..d234724 100644
--- a/sr_port/repl_errno.h
+++ b/sr_port/repl_errno.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -48,11 +48,10 @@ enum
 	EREPL_INTLFILTER_DATA2LONG,		/* 285 */
 	EREPL_INTLFILTER_REPLGBL2LONG,		/* 286 */
 	EREPL_FILTERRECV,			/* 287 */
-	EREPL_FILTERNOSPC,			/* 288 */
-	EREPL_INTLFILTER_SECNODZTRIGINTP,	/* 289 */
-	EREPL_INTLFILTER_MULTILINEXECUTE,	/* 290 */
-	EREPL_FILTERTIMEDOUT,			/* 291 */
-	EREPL_MAXERRNO				/* 292 */
+	EREPL_INTLFILTER_PRILESSTHANV62,	/* 288 */
+	EREPL_INTLFILTER_SECLESSTHANV62,	/* 289 */
+	EREPL_FILTERTIMEDOUT,			/* 290 */
+	EREPL_MAXERRNO				/* 291 */
 };
 
 #endif
diff --git a/sr_port/repl_filter.c b/sr_port/repl_filter.c
index 6a9d933..11743c8 100644
--- a/sr_port/repl_filter.c
+++ b/sr_port/repl_filter.c
@@ -60,35 +60,37 @@
 #include "gtm_c_stack_trace.h"
 #include "fork_init.h"
 #endif
-#ifdef DEBUG
 #include "wbox_test_init.h"
-#endif
 #ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
 #include <sys/poll.h>
 #endif
+#ifdef GTM_TRIGGER
+#include "trigger.h"
+#endif
 
-#define NULLSUBSC_TRANSFORM_IF_NEEDED(PTR)					\
-{										\
-	int			keylen;						\
-	uchar_ptr_t		lclptr;						\
-	DCL_THREADGBL_ACCESS;							\
-										\
-	SETUP_THREADGBL_ACCESS;							\
-	if (REMOTE_NULL_SUBS_XFORM)						\
-	{									\
-		assert(SIZEOF(jnl_str_len_t) == SIZEOF(uint4));			\
-		keylen = *((jnl_str_len_t *)(PTR));				\
-		keylen &= 0xFFFFFF;	/* to remove 8-bit nodeflags if any */	\
-		lclptr = PTR + SIZEOF(jnl_str_len_t);				\
-		if (STDNULL_TO_GTMNULL_COLL == REMOTE_NULL_SUBS_XFORM)		\
-		{								\
-			STD2GTMNULLCOLL(lclptr, keylen);			\
-		} else								\
-		{								\
-			GTM2STDNULLCOLL(lclptr, keylen);			\
-		}								\
-	}									\
-}										\
+/* Do not apply null subscript transformations to LGTRIG and ZTWORM type records */
+#define NULLSUBSC_TRANSFORM_IF_NEEDED(RECTYPE, PTR)					\
+{											\
+	int			keylen;							\
+	uchar_ptr_t		lclptr;							\
+	DCL_THREADGBL_ACCESS;								\
+											\
+	SETUP_THREADGBL_ACCESS;								\
+	if (!IS_ZTWORM(rectype) && !IS_LGTRIG(rectype) && REMOTE_NULL_SUBS_XFORM)	\
+	{										\
+		assert(SIZEOF(jnl_str_len_t) == SIZEOF(uint4));				\
+		keylen = *((jnl_str_len_t *)(PTR));					\
+		keylen &= 0xFFFFFF;	/* to remove 8-bit nodeflags if any */		\
+		lclptr = PTR + SIZEOF(jnl_str_len_t);					\
+		if (STDNULL_TO_GTMNULL_COLL == REMOTE_NULL_SUBS_XFORM)			\
+		{									\
+			STD2GTMNULLCOLL(lclptr, keylen);				\
+		} else									\
+		{									\
+			GTM2STDNULLCOLL(lclptr, keylen);				\
+		}									\
+	}										\
+}											\
 
 #define BREAK_IF_BADREC(RECLEN, STATUS)				\
 {								\
@@ -202,7 +204,8 @@
 	nodelen = *((uint4 *)jb);										\
 	assert(tail_minus_suffix_len >= (SIZEOF(jnl_str_len_t) + nodelen));					\
 	memcpy(cb, jb, tail_minus_suffix_len);									\
-	NULLSUBSC_TRANSFORM_IF_NEEDED(cb);									\
+	/* V17 did not support triggers, no need to send the actual rectype */					\
+	NULLSUBSC_TRANSFORM_IF_NEEDED(SET_KILL_ZKILL_MASK , cb);						\
 	jb += tail_minus_suffix_len;										\
 	cb += tail_minus_suffix_len;										\
 }
@@ -272,7 +275,8 @@
 	 */													\
 	((jnl_string *)cb)->nodeflags = 0;									\
 	GET_JREC_UPD_TYPE(jb, trigupd_type);									\
-	NULLSUBSC_TRANSFORM_IF_NEEDED(cb);									\
+	/* Caller excludes ZTWORM and LGTRIG already, no need to send the actual rectype */			\
+	NULLSUBSC_TRANSFORM_IF_NEEDED(SET_KILL_ZKILL_MASK , cb);						\
 	jb += tail_minus_suffix_len;										\
 	cb += tail_minus_suffix_len;										\
 }
@@ -408,26 +412,28 @@ enum
 
 GBLDEF	intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] =
 {
-	IF_24TO17,	/* Convert from filter format V24 to V17 (i.e., from jnl ver V24 to V17) */
-	IF_24TO17,	/* Convert from filter format V24 to V17 (i.e., from jnl ver V24 to V18) */
-	IF_24TO19,	/* Convert from filter format V24 to V19 (i.e., from jnl ver V24 to V19) */
-	IF_24TO19,	/* Convert from filter format V24 to V19 (i.e., from jnl ver V24 to V20) */
-	IF_24TO21,	/* Convert from filter format V24 to V21 (i.e., from jnl ver V24 to V21) */
-	IF_24TO22,	/* Convert from filter format V24 to V22 (i.e., from jnl ver V24 to V22) */
-	IF_24TO22,	/* Convert from filter format V24 to V22 (i.e., from jnl ver V24 to V23) */
-	IF_24TO24	/* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V24) */
+	IF_24TO17,	/* Convert from filter format V24 to V17 (i.e., from jnl ver V25 to V17) */
+	IF_24TO17,	/* Convert from filter format V24 to V17 (i.e., from jnl ver V25 to V18) */
+	IF_24TO19,	/* Convert from filter format V24 to V19 (i.e., from jnl ver V25 to V19) */
+	IF_24TO19,	/* Convert from filter format V24 to V19 (i.e., from jnl ver V25 to V20) */
+	IF_24TO21,	/* Convert from filter format V24 to V21 (i.e., from jnl ver V25 to V21) */
+	IF_24TO22,	/* Convert from filter format V24 to V22 (i.e., from jnl ver V25 to V22) */
+	IF_24TO22,	/* Convert from filter format V24 to V22 (i.e., from jnl ver V25 to V23) */
+	IF_24TO24,	/* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V24) */
+	IF_24TO24	/* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V25) */
 };
 
 GBLDEF	intlfltr_t repl_filter_old2cur[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] =
 {
-	IF_17TO24,	/* Convert from filter format V17 to V24 (i.e., from jnl ver V17 to V24) */
-	IF_17TO24,	/* Convert from filter format V17 to V24 (i.e., from jnl ver V18 to V24) */
-	IF_19TO24,	/* Convert from filter format V19 to V24 (i.e., from jnl ver V19 to V24) */
-	IF_19TO24,	/* Convert from filter format V19 to V24 (i.e., from jnl ver V20 to V24) */
-	IF_21TO24,	/* Convert from filter format V21 to V24 (i.e., from jnl ver V21 to V24) */
-	IF_22TO24,	/* Convert from filter format V22 to V24 (i.e., from jnl ver V22 to V24) */
-	IF_22TO24,	/* Convert from filter format V22 to V24 (i.e., from jnl ver V23 to V24) */
-	IF_24TO24	/* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V24) */
+	IF_17TO24,	/* Convert from filter format V17 to V24 (i.e., from jnl ver V17 to V25) */
+	IF_17TO24,	/* Convert from filter format V17 to V24 (i.e., from jnl ver V18 to V25) */
+	IF_19TO24,	/* Convert from filter format V19 to V24 (i.e., from jnl ver V19 to V25) */
+	IF_19TO24,	/* Convert from filter format V19 to V24 (i.e., from jnl ver V20 to V25) */
+	IF_21TO24,	/* Convert from filter format V21 to V24 (i.e., from jnl ver V21 to V25) */
+	IF_22TO24,	/* Convert from filter format V22 to V24 (i.e., from jnl ver V22 to V25) */
+	IF_22TO24,	/* Convert from filter format V22 to V24 (i.e., from jnl ver V23 to V25) */
+	IF_24TO24,	/* Convert from filter format V24 to V24 (i.e., from jnl ver V24 to V25) */
+	IF_24TO24	/* Convert from filter format V24 to V24 (i.e., from jnl ver V25 to V25) */
 };
 
 GBLREF	unsigned int		jnl_source_datalen, jnl_dest_maxdatalen;
@@ -447,6 +453,8 @@ GBLREF boolean_t		heartbeat_started;
 #endif
 GBLREF	uint4			process_id;
 
+LITREF	char			*trigger_subs[];
+
 error_def(ERR_FILTERBADCONV);
 error_def(ERR_FILTERCOMM);
 error_def(ERR_FILTERNOTALIVE);
@@ -631,7 +639,8 @@ int repl_filter_init(char *filter_cmd)
 			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLFILTER, 0, ERR_TEXT, 2,
 					RTS_ERROR_LITERAL("Could not exec filter"), ERRNO);
 			repl_errno = EREPL_FILTERSTART_EXEC;
-			return(FILTERSTART_ERR);
+			UNIX_ONLY(_exit(FILTERSTART_ERR);)
+			VMS_ONLY(return(FILTERSTART_ERR);) /* maintain existing for VMS */
 		}
 	} else
 	{	/* Error in fork */
@@ -1201,53 +1210,6 @@ void repl_check_jnlver_compat(UNIX_ONLY(boolean_t same_endianness))
 #	endif
 }
 
-static void upgrd_V19_hasht_xecute_string_to_V24(uchar_ptr_t jb, uchar_ptr_t cb, jnl_string *keystr, char *xecute_val_ptr,
-		uint4 *conv_reclen)
-{	/* Upgrade the ^#t("GBL",1,"XECUTE") node's value to the xecute string format supported in V5.4-002 (and later).
-	 * Before V5.4-002, the xecute string is stored as-is in the database. But, from V5.4-002, the xecute string is
-	 * stored differently based on whether it is a single-line trigger xecute string or a multi-line trigger xecute
-	 * string. If former, the xecute string is prefixed with a <SPACE> character. If latter, no <SPACE> is prefixed.
-	 * Since, V5.4-001 does NOT support multi-line triggers, all we need is to prefix the xecute string with <SPACE>
-	 */
-	 uint4			tmp_jrec_size, jrec_size, align_fill_size;
-	 uchar_ptr_t		srcptr;
-	 int			valstrlen, new_valstrlen;
-
-	/* An update-type journal record is formatted as follows:
-	 *
-	 * [FIXED_UPD_RECLEN][KEYLEN][NODEFLAGS][KEY][\0][VALUE_LEN][VALUE][PADDING_ZEROS][JREC_SUFFIX_SIZE]
-	 *
-	 * The input parameter 'xecute_val_ptr' points to the beginning of VALUE_LEN in the above journal format. Since
-	 * <SPACE> is added to the xecute string, this will affect the VALUE_LEN, PADDING_ZEROS, record length.
-	 * Note: 'cb' already has a copy of 'jb' and 'xecute_val_ptr' is a pointer inside 'cb'
-	 */
-	GET_MSTR_LEN(valstrlen, xecute_val_ptr); 	/* get the length of the value */
-	new_valstrlen = valstrlen + 1;
-	PUT_MSTR_LEN(xecute_val_ptr, new_valstrlen);
-	/* new record size and padding byte calculations */
-	tmp_jrec_size = FIXED_UPD_RECLEN
-				+ SIZEOF(jnl_str_len_t) + keystr->length
-				+ SIZEOF(mstr_len_t) + (valstrlen + 1)
-				+ JREC_SUFFIX_SIZE;
-	jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); /* new record size (aligned to 8 byte boundary) */
-	align_fill_size = jrec_size - tmp_jrec_size; /* necessary padding bytes */
-	/* add <SPACE> and copy the xecute string */
-	xecute_val_ptr += SIZEOF(mstr_len_t);		/* move to the beginning of the 'value' */
-	srcptr = jb + ((uchar_ptr_t)xecute_val_ptr - cb - 8);	/* pointer to the xecute string from the source buffer.
-								 * -8 needed because "strm_seqno" is absent in source. */
-	*xecute_val_ptr++ = ' ';			/* add the much needed <SPACE> */
-	memcpy(xecute_val_ptr, srcptr, valstrlen);	/* copy the actual xecute string */
-	xecute_val_ptr += valstrlen;
-	memset(xecute_val_ptr, 0, align_fill_size);	/* padding zeros for 8 byte alignment */
-	xecute_val_ptr += align_fill_size;		/* points to suffix */
-	/* fill suffix */
-	((jrec_suffix *)(xecute_val_ptr))->backptr = jrec_size;
-	((jrec_suffix *)(xecute_val_ptr))->suffix_code = JNL_REC_SUFFIX_CODE;
-	assert((0 != *conv_reclen) && !(*conv_reclen % JNL_REC_START_BNDRY));
-	if (*conv_reclen != jrec_size)
-		((jrec_prefix *)(cb))->forwptr = *conv_reclen = jrec_size;
-}
-
 /* The following code defines the functions that convert one jnl format to another.
  * The only replicated records we expect to see here are *SET* or *KILL* or TCOM or NULL records.
  * These fall under the following 3 structure types each of which is described for the different jnl formats we handle.
@@ -1336,6 +1298,7 @@ static void upgrd_V19_hasht_xecute_string_to_V24(uchar_ptr_t jb, uchar_ptr_t cb,
  *	This means, we need to have 8 more bytes in the conversion buffer for NULL type of records.
  * (d) If the null collation is different between primary and secondary (null_subs_xform) then appropriate conversion
  *     is needed
+ * (e) Note that V17 did not support triggers so dont need to check for ^#t or ZTRIG or ZTWORM or LGTRIG records.
  * Reformat accordingly.
  */
 int jnl_v17TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
@@ -1432,7 +1395,7 @@ int jnl_v17TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
  * (a) Since the remote side (V17) does NOT support triggers, skip ^#t, ZTWORM/LGTRIG/ZTRIG journal records
  *	& reset nodeflags (if set). If the entire transaction consists of skipped records, send a NULL record instead.
  *
- * Note: Although (1) is trigger specific, the logic should be available for trigger non-supporting platorms as well to
+ * Note: Although (a) is trigger specific, the logic should be available for trigger non-supporting platorms as well to
  * handle replication scenarios like V5.4-001 (TS) -> V5.4-002 (NTS) -> V4.4-004 (NTS) where TS indicates a trigger supporting
  * platform and NTS indicates either a version without trigger support OR is running on trigger non-supporting platform.
  */
@@ -1446,7 +1409,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 	jrec_prefix 		*prefix;
 	seq_num			this_upd_seqno;
 	uint4 			trigupd_type = NO_TRIG_JREC;
-	DEBUG_ONLY(boolean_t	non_ztrig_rec_found = FALSE;)
+	DEBUG_ONLY(boolean_t	non_trig_rec_found = FALSE;)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -1490,10 +1453,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 			jb += t_len;
 			if (is_set_kill_zkill_ztrig)
 			{
-				DEBUG_ONLY(
-					if (!IS_ZTRIG(rectype))
-						non_ztrig_rec_found = TRUE;
-				)
+				DEBUG_ONLY(non_trig_rec_found = TRUE;)
 				assert((cb - cstart) == (OFFSETOF(struct_jrec_upd, token_seq) + SIZEOF(token_seq_t)));
 				/* side-effect: increments cb and jb and GTM Null Collation or Standard Null Collation applied */
 				INITIALIZE_V17_MUMPS_NODE_FROM_V24(cstart, cb, jstart, jb, trigupd_type, FALSE);
@@ -1586,7 +1546,7 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 			 * (b) If the only records in a transaction are ZTRIG records and a TCOM record.
 			 * In both the above cases we need to send a NULL record instead.
 			 */
-			assert((HASHT_JREC == trigupd_type) || (FALSE == non_ztrig_rec_found));
+			assert((HASHT_JREC == trigupd_type) || (FALSE == non_trig_rec_found));
 			prefix = (jrec_prefix *)(cb);
 			if (V17_NULL_RECLEN > conv_bufsiz)
 			{
@@ -1610,8 +1570,8 @@ int jnl_v24TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
  * (b) If the receiver side does NOT support triggers, then skip ^#t/ZTWORM journal records & reset nodeflags (if set).
  *	Note that V19 did not support ZTRIG or LGTRIG records so dont need to check for them.
  *	If the entire transaction consists of skipped records, send a NULL record instead.
- * (c) If receiver side does support triggers, then fix ^#t("GBL","#LABEL") and ^#t("GBL",1,"XECUTE") to reflect newer format.
- *
+ * (c) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ *	the replication stream from V62001 onwards.
  * Note : For both (a) and (b), ZTRIG type of records are not possible in V19 (they start only from V21).
  * Reformat accordingly.
  */
@@ -1676,6 +1636,14 @@ int jnl_v19TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 						jb = jb + reclen;
 						jlen -= reclen;
 						continue;
+					} else if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed to V24,
+						 * only LGTRIG records are. But since the source version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+						status = -1;
+						break;
 					}
 				} else if (HASHT_JREC == trigupd_type)
 				{	/* Journal record has a #t global. #t records are not replicated if the secondary does not
@@ -1696,38 +1664,9 @@ int jnl_v19TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				memcpy(cb + V19_UPDATE_NUM_OFFSET + 8, jb + V19_UPDATE_NUM_OFFSET,
 					conv_reclen - 8 - V19_UPDATE_NUM_OFFSET);
 				mumps_node_ptr = cstart + V24_MUMPS_NODE_OFFSET;
-				if (HASHT_JREC == trigupd_type)
-				{	/* ^#t record */
-					assert(receiver_supports_triggers);
-					keystr = (jnl_string *)mumps_node_ptr;
-					keyend = &keystr->text[keystr->length - 1];
-					if (!MEMCMP_LIT((keyend - LITERAL_HASHLABEL_LEN), LITERAL_HASHLABEL))
-					{	/* ^#t("GBL","#LABEL") found. Adjust the value of this node to be equal to
-						 * HASHT_GBL_CURLABEL as the secondary is the latest trigger supported version.
-						 * But, we should do this ONLY if this is a SET record.
-						 */
-						if (IS_SET(rectype))
-						{	/* Upgrade the #LABEL to the current version's #LABEL */
-							/* '+ 1' below is to account for '- 1' done above */
-							ptr = keyend + SIZEOF(mstr_len_t) + 1;
-							assert(0 == MEMCMP_LIT(ptr, V19_HASHT_GBL_LABEL));
-							assert(STR_LIT_LEN(HASHT_GBL_CURLABEL) == STR_LIT_LEN(V19_HASHT_GBL_LABEL));
-							MEMCPY_LIT(ptr, HASHT_GBL_CURLABEL);
-						}
-					} else if (!MEMCMP_LIT(keyend - LITERAL_XECUTE_LEN, LITERAL_XECUTE))
-					{	/* ^#t("GBL",1,"XECUTE") found. Upgrade it to the current version's XECUTE format */
-						assert(IS_SET(rectype)); /* This better be a SET record */
-						if (IS_SET(rectype))
-						{	/* do the upgrade in PRO only if this is a SET record */
-							upgrd_V19_hasht_xecute_string_to_V24(jb, cb, keystr, keyend + 1,
-												&conv_reclen);
-							assert(0 == conv_reclen % JNL_REC_START_BNDRY);
-						}
-					}
-				}
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -1836,9 +1775,9 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 	jrec_prefix 		*prefix;
 	seq_num			this_upd_seqno;
 	uint4 			trigupd_type = NO_TRIG_JREC;
-	boolean_t		promote_uupd_to_tupd, hasht_update_found, normal_update_found, receiver_supports_triggers;
+	boolean_t		promote_uupd_to_tupd, receiver_supports_triggers;
 	boolean_t		hasht_seen;
-	DEBUG_ONLY(boolean_t	non_ztrig_rec_found = FALSE;)
+	DEBUG_ONLY(boolean_t	non_trig_rec_found = FALSE;)
 	jnl_string		*keystr;
 	DCL_THREADGBL_ACCESS;
 
@@ -1848,7 +1787,7 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 	status = SS_NORMAL;
 	jlen = *jnl_len;
 	QWASSIGN(this_upd_seqno, seq_num_zero);
-	promote_uupd_to_tupd = hasht_update_found = normal_update_found = FALSE;
+	promote_uupd_to_tupd = FALSE;
 	hasht_seen = FALSE;
 	assert(is_src_server);
 	/* Since this filter function will be invoked only on the source side, the check for whether the receiver
@@ -1897,15 +1836,19 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 			if (IS_SET_KILL_ZKILL_ZTWORM(rectype))
 			{
 				assert((cb == cstart) && (jb == jstart));
-				DEBUG_ONLY(
-					if (!IS_ZTRIG(rectype))
-						non_ztrig_rec_found = TRUE;
-				)
+				DEBUG_ONLY(non_trig_rec_found = TRUE;)
 				GET_JREC_UPD_TYPE(jb + V24_MUMPS_NODE_OFFSET, trigupd_type);
 				if (receiver_supports_triggers)
 				{
-					if (!normal_update_found)
-						normal_update_found = (HASHT_JREC != trigupd_type);
+					if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed from V24,
+						 * only LGTRIG records are. But since the receiver version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+						status = -1;
+						break;
+					}
 					if (NON_REPLIC_JREC_TRIG == trigupd_type)
 					{
 						if (IS_TUPD(rectype))
@@ -1931,57 +1874,9 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				/* t_len bytes have already been copied. Skip 8-byte strm_seqno (absent in V19) and copy rest */
 				memcpy(cb + t_len, jb + t_len + 8, conv_reclen - t_len);
 				mumps_node_ptr = (cb + V19_MUMPS_NODE_OFFSET);
-				if (HASHT_JREC == trigupd_type)
-				{
-					assert(receiver_supports_triggers);
-					if (!hasht_update_found)
-						hasht_update_found = TRUE;
-					/* Since the secondary side is running on an older trigger-supporting version than the
-					 * primary, the ^#t("GBL","#LABEL") value needs to be adjusted to have the value that the
-					 * secondary will understand. Not doing so will cause the secondary to issue TRIGDEFBAD
-					 * error.
-					 */
-					keystr = (jnl_string *)mumps_node_ptr;
-					keyend = &keystr->text[keystr->length - 1];
-					assert('\0' == *keyend); /* we better have a null terminator at the end of the key */
-					if (!MEMCMP_LIT((keyend - LITERAL_HASHLABEL_LEN), LITERAL_HASHLABEL))
-					{	/* ^#t("GBL","#LABEL") found. For details on the update record layout, see the
-						 * comment in upgrd_hasht_xecute_string
-						 */
-						ptr = keyend + SIZEOF(mstr_len_t) + 1; /* '+ 1' to account for '- 1' done above */
-						assert(0 == MEMCMP_LIT(ptr, HASHT_GBL_CURLABEL));
-						assert(STR_LIT_LEN(HASHT_GBL_CURLABEL) == STR_LIT_LEN(V19_HASHT_GBL_LABEL));
-						MEMCPY_LIT(ptr, V19_HASHT_GBL_LABEL);
-					} else if (0x80 == (unsigned char)(*(keyend - 1)))
-					{	/* last subscript is zero. Check if the preceding subscript is "XECUTE" */
-						ptr = keyend - 2; /* -1 for 0x80 and -1 for null terminator */
-						if (!MEMCMP_LIT((ptr - LITERAL_XECUTE_LEN), LITERAL_XECUTE))
-						{	/* preceding subscript is "XECUTE". Ensure the preceding character is \0 */
-							ptr -= (LITERAL_XECUTE_LEN + 1); /* +1 for the leading \0 */
-							assert(STR_SUB_PREFIX == ((unsigned char)(*ptr)));
-							if (STR_SUB_PREFIX == ((unsigned char)(*ptr)))
-							{	/* found ^#t("GBL",1,"XECUTE",0) which V5.4-001 secondary does
-								 * NOT understand
-								 */
-								repl_errno = EREPL_INTLFILTER_MULTILINEXECUTE;
-								status = -1;
-								break;
-							}
-						}
-					}
-				}
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				else if (hasht_update_found && normal_update_found)
-				{	/* A mix of ^#t updates and normal updates. Secondary (V5.4-000 to V5.4-001) does not
-					 * understand mix of such updates. Set error status and break. Replication cannot
-					 * continue unless $ztrigger() in TP (along with other updates) is eliminated.
-					 */
-					repl_errno = EREPL_INTLFILTER_SECNODZTRIGINTP;
-					status = -1;
-					break;
-				}
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2032,7 +1927,7 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 			 * (b) If the only records in a transaction are ZTRIG records and a TCOM record.
 			 * In both the above cases we need to send a NULL record instead.
 			 */
-			assert((HASHT_JREC == trigupd_type) || (FALSE == non_ztrig_rec_found));
+			assert((HASHT_JREC == trigupd_type) || (FALSE == non_trig_rec_found));
 			prefix = (jrec_prefix *)(cb);
 			if (NULL_RECLEN > conv_bufsiz)
 			{
@@ -2058,10 +1953,11 @@ int jnl_v24TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
  * (b) If the receiver side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
  *	Note that V21 did not support LGTRIG records so dont need to check for them.
  *	If the entire transaction consists of skipped records, send a NULL record instead.
+ * (c) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ *	the replication stream from V62001 onwards.
  * Reformat accordingly.
  * Note: This function (jnl_v21TOv24) is somewhat similar to jnl_v19TOv24 except that ZTRIG records can be seen in v21
- * whereas it cannot be in v19. In addition, no ^#t("GBL","#LABEL") or ^#t("GBL",1,"XECUTE") conversions are needed
- * since the ^#t format is unchanged between V21 and V24.
+ * whereas it cannot be in v19.
  */
 int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
 {
@@ -2134,6 +2030,14 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 						jb = jb + reclen;
 						jlen -= reclen;
 						continue;
+					} else if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed to V24,
+						 * only LGTRIG records are. But since the source version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+						status = -1;
+						break;
 					}
 				} else if (HASHT_JREC == trigupd_type)
 				{	/* Journal record has a #t global. #t records are not replicated if the secondary
@@ -2159,7 +2063,7 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				/* V21 and V24 have same ^#t("GBL","#LABEL") value so no need to fix like is done for V19 to V24 */
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2243,7 +2147,7 @@ int jnl_v21TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
  * For differences between the two versions, see the comment in jnl_v19TOv24. In addition, take care of the following.
  * (a) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG/LGTRIG journal records.
  *	If the entire transaction consists of skipped records, send a NULL record instead.
- * (b) If remote side does support triggers, then skip LGTRIG journal records as they are not known to the older journal format.
+ * (b) If remote side supports triggers, then error out for LGTRIG journal records as they are unknown to the older journal format.
  * Note: This function (jnl_v21TOv24) is somewhat similar to jnl_v24TOv19 except that ZTRIG records can be seen in v21
  * whereas it cannot be in v19. In addition, no ^#t("GBL","#LABEL") or ^#t("GBL",1,"XECUTE") conversions are needed
  * since the ^#t format is unchanged between V21 and V24.
@@ -2323,6 +2227,15 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				GET_JREC_UPD_TYPE(jb + V24_MUMPS_NODE_OFFSET, trigupd_type);
 				if (receiver_supports_triggers)
 				{
+					if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed from V24,
+						 * only LGTRIG records are. But since the receiver version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+						status = -1;
+						break;
+					}
 					if (NON_REPLIC_JREC_TRIG == trigupd_type)
 					{
 						if (IS_TUPD(rectype))
@@ -2352,7 +2265,7 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				mumps_node_ptr = (cb + V19_MUMPS_NODE_OFFSET);
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2424,7 +2337,9 @@ int jnl_v24TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
  * (a) If null-subscript collation is different between the primary and the secondary
  * (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
  *	Note that V22 did not support LGTRIG records so dont need to check for them.
- * (c)	If the entire transaction consists of skipped records, send a NULL record instead.
+ * (c) If the entire transaction consists of skipped records, send a NULL record instead.
+ * (d) If receiver side does support triggers, then issue error if ^#t records are found as those are not allowed in
+ *	the replication stream from V62001 onwards.
  */
 int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz)
 {
@@ -2467,7 +2382,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 			this_strm_seqno = GET_STRM_SEQNO(jb);
 		}
 		assert(IS_REPLICATED(rectype));
-		assert(JRT_MAX_V23 >= rectype);
+		assert(JRT_MAX_V22 >= rectype);
 		if (IS_TUPD(rectype))
 			promote_uupd_to_tupd = FALSE;
 		if (!receiver_supports_triggers && (IS_ZTRIG(rectype) || IS_ZTWORM(rectype)))
@@ -2499,6 +2414,14 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 						jb = jb + reclen;
 						jlen -= reclen;
 						continue;
+					} else if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed to V24,
+						 * only LGTRIG records are. But since the source version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_PRILESSTHANV62;
+						status = -1;
+						break;
 					}
 				} else if (HASHT_JREC == trigupd_type)
 				{	/* Journal record has a #t global. #t records are not replicated if the secondary does not
@@ -2519,7 +2442,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				mumps_node_ptr = cb + FIXED_UPD_RECLEN;
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2586,7 +2509,7 @@ int jnl_v22TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 /* Convert a transaction from jnl version V24 (V6.2-000 onwards) to V22/V23 (V5.5-000 thru V6.1-000).
  * (a) If null-subscript collation is different between the primary and the secondary
  * (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/ZTRIG journal records & reset nodeflags (if set).
- *	Note that V22 did not support LGTRIG records so dont need to check for them.
+ *	Note that V22 did not support LGTRIG records so issue an error.
  * (c) If remote side does support triggers, then skip LGTRIG journal records as they are not known to the older journal format.
  * (d)	If the entire transaction consists of skipped records, send a NULL record instead.
  */
@@ -2656,6 +2579,15 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				GET_JREC_UPD_TYPE((jb + FIXED_UPD_RECLEN), trigupd_type);
 				if (receiver_supports_triggers)
 				{
+					if (HASHT_JREC == trigupd_type)
+					{	/* Journal record has a #t global. #t records are no longer allowed from V24,
+						 * only LGTRIG records are. But since the receiver version does not support
+						 * LGTRIG records, issue error.
+						 */
+						repl_errno = EREPL_INTLFILTER_SECLESSTHANV62;
+						status = -1;
+						break;
+					}
 					if (NON_REPLIC_JREC_TRIG == trigupd_type)
 					{
 						if (IS_TUPD(rectype))
@@ -2684,7 +2616,7 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				mumps_node_ptr = cb + FIXED_UPD_RECLEN;
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
@@ -2749,7 +2681,7 @@ int jnl_v24TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 	return(status);
 }
 
-/* Convert a transaction from jnl version V24 (V6.2-000 onwards) to V24 (V6.2-000 onwards).
+/* Convert a transaction from filter format V24 (V6.2-000 onwards) to V24 (V6.2-000 onwards).
  * Same version filters are needed if one of the below is true.
  * (a) If null-subscript collation is different between the primary and the secondary
  * (b) If the remote side does NOT support triggers, then skip ^#t/ZTWORM/LGTRIG/ZTRIG journal records & reset nodeflags (if set).
@@ -2776,12 +2708,15 @@ int jnl_v24TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 	jlen = *jnl_len;
 	this_upd_seqno = seq_num_zero;
 	promote_uupd_to_tupd = FALSE;
-	/* The following assert ensures that filtering is initiated by the responsible party and in the expected direction. */
-	assert(is_src_server);
-	/* Since this filter function will be invoked only on the source side, the check for whether the receiver
-	 * supports triggers is equal to checking whether the REMOTE side supports triggers.
+	/* Since filter format V24 corresponds to journal format V24 or V25, in case of a V24 source and V25 receiver,
+	 * the source server will not do any filter transformations (because receiver jnl ver is higher). This means
+	 * jnl_v24TOv24 filter conversion function will be invoked on the receiver side to do V24 to V25 jnl format conversion.
+	 * Therefore we cannot do an assert(is_src_server) which we otherwise would have had in case the latest filter
+	 * version corresponds to only ONE journal version.
+	 *	assert(is_src_server);
 	 */
-	receiver_supports_triggers = REMOTE_TRIGGER_SUPPORT;
+	assert(is_src_server || is_rcvr_server);
+	receiver_supports_triggers = (is_src_server ? REMOTE_TRIGGER_SUPPORT : LOCAL_TRIGGER_SUPPORT);
 	GTMTRIG_ONLY(assert(receiver_supports_triggers);)	/* if receiver is V24 format, it should have been built
 								 * with trigger support enabled since we dont either build
 								 * anymore OR replicate anymore to trigger unsupported platforms
@@ -2850,7 +2785,7 @@ int jnl_v24TOv24(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui
 				mumps_node_ptr = cb + FIXED_UPD_RECLEN;
 				if (!receiver_supports_triggers)
 					((jnl_string *)mumps_node_ptr)->nodeflags = 0;
-				NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr);
+				NULLSUBSC_TRANSFORM_IF_NEEDED(rectype, mumps_node_ptr);
 				if (IS_TUPD(rectype))
 					tupd_num++;
 				else if (IS_UUPD(rectype) && promote_uupd_to_tupd)
diff --git a/sr_port/repl_filter.h b/sr_port/repl_filter.h
index 2d80eda..c058ea9 100644
--- a/sr_port/repl_filter.h
+++ b/sr_port/repl_filter.h
@@ -69,6 +69,7 @@ typedef int (*intlfltr_t)(uchar_ptr_t, uint4 *, uchar_ptr_t, uint4 *, uint4);
  *	V22	V22	GT.M V5.5-000	strm_seqno added to all logical records (supplementary instances)
  *	V22	V23	GT.M V6.0-000	Various journaling-related limits have changed, allowing for much larger journal records
  *	V24	V24	GT.M V6.2-000	New logical trigger journal record (TLGTRIG and ULGTRIG jnl records)
+ *	V24	V25	GT.M V6.2-001	No new jnl record but bump needed to replicate logical trigger jnl records (GTM-7509)
  */
 
 typedef enum
@@ -92,6 +93,7 @@ typedef enum
 	REPL_JNL_V22,		/* enum corresponding to journal format V22 */
 	REPL_JNL_V23,		/* enum corresponding to journal format V23 */
 	REPL_JNL_V24,		/* enum corresponding to journal format V24 */
+	REPL_JNL_V25,		/* enum corresponding to journal format V25 */
 	REPL_JNL_MAX
 } repl_jnl_t;
 
@@ -140,6 +142,8 @@ GBLREF	intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1];
  * 	EREPL_INTLFILTER_INCMPLREC - incomplete record in the filter buffer.
  *	EREPL_INTLFILTER_NEWREC - cannot convert record, the record is newer than the "to" version.
  *	EREPL_INTLFILTER_REPLGBL2LONG - record contains global name > 8 characters, which is not supported in remote side
+ *	EREPL_INTLFILTER_SECLESSTHANV62 - record contains #t global which is not allowed when source side is > V62000
+ *	EREPL_INTLFILTER_PRILESSTHANV62 - record contains #t global which is not allowed when receiver side is > V62000
  * In all error cases, conv_len will be the offset at which processing was stopped.
  */
 
@@ -156,6 +160,7 @@ GBLREF	intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1];
 #define V22_JNL_VER		22
 #define V23_JNL_VER		23
 #define V24_JNL_VER		24
+#define V25_JNL_VER		25
 
 #define	V17_NULL_RECLEN		40	/* size of a JRT_NULL record in V17/V18 jnl format */
 #define	V19_NULL_RECLEN		40	/* size of a JRT_NULL record in V19/V20 jnl format */
@@ -252,19 +257,28 @@ void repl_filter_error(seq_num filter_seqno, int why);
 	assert(0 < OUT_BUFSIZ);									\
 }
 
+/* Below error_defs are needed by the following macros */
+error_def(ERR_REPLRECFMT);
+error_def(ERR_REPLGBL2LONG);
+error_def(ERR_REPLNOHASHTREC);
+
 #ifdef UNIX
-# define INT_FILTER_RTS_ERROR(FILTER_SEQNO)								\
-{													\
-	if (EREPL_INTLFILTER_BADREC == repl_errno)							\
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLRECFMT);				\
-	else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)						\
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);				\
-	else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)					\
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, &FILTER_SEQNO);	\
-	else if (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno)					\
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLNOMULTILINETRG, 1, &FILTER_SEQNO);	\
-	else	/* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */					\
-		assertpro(FALSE);									\
+# define INT_FILTER_RTS_ERROR(FILTER_SEQNO, REPL_ERRNO)										\
+{																\
+	assert((EREPL_INTLFILTER_BADREC == REPL_ERRNO)										\
+		|| (EREPL_INTLFILTER_REPLGBL2LONG == REPL_ERRNO)								\
+		|| (EREPL_INTLFILTER_PRILESSTHANV62 == REPL_ERRNO)								\
+		|| (EREPL_INTLFILTER_SECLESSTHANV62 == REPL_ERRNO));								\
+	if (EREPL_INTLFILTER_BADREC == REPL_ERRNO)										\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLRECFMT);							\
+	else if (EREPL_INTLFILTER_REPLGBL2LONG == REPL_ERRNO)									\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);							\
+	else if (EREPL_INTLFILTER_PRILESSTHANV62 == REPL_ERRNO)									\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLNOHASHTREC, 3, &FILTER_SEQNO, LEN_AND_LIT("Source"));		\
+	else if (EREPL_INTLFILTER_SECLESSTHANV62 == REPL_ERRNO)									\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLNOHASHTREC, 3, &FILTER_SEQNO, LEN_AND_LIT("Receiver"));	\
+	else	/* (EREPL_INTLFILTER_INCMPLREC == REPL_ERRNO) */								\
+		assertpro(FALSE);												\
 }
 #else
 # define INT_FILTER_RTS_ERROR(FILTER_SEQNO)					\
diff --git a/sr_port/rtn_src_chksum.c b/sr_port/rtn_src_chksum.c
index 599b4ec..1095f14 100644
--- a/sr_port/rtn_src_chksum.c
+++ b/sr_port/rtn_src_chksum.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -31,7 +31,12 @@ error_def(ERR_FILENOTFND);
 
 void rtn_src_chksum_init(gtm_rtn_src_chksum_ctx *ctx)
 {
+#	ifdef UNIX
+	HASH128_STATE_INIT(ctx->hash_state, 0);
+	ctx->total_size = 0;
+#	else
 	cvs_MD5Init(&ctx->md5ctx);
+#	endif
 }
 
 /*
@@ -40,16 +45,28 @@ void rtn_src_chksum_init(gtm_rtn_src_chksum_ctx *ctx)
 
 void rtn_src_chksum_line(gtm_rtn_src_chksum_ctx *ctx, const void *data, uint4 len)
 {
+#	ifdef UNIX
+	gtmmrhash_128_ingest(&ctx->hash_state, data, len);
+	ctx->total_size += len;
+#	else
 	cvs_MD5Update(&ctx->md5ctx, data, len);
+#	endif
 }
 
 /*
- * Finished computing checksum. Fill in digest[] array from MD5 context.
+ * Finished computing checksum. Fill in digest[] array.
  */
 
 void rtn_src_chksum_digest(gtm_rtn_src_chksum_ctx *ctx)
 {
+#	ifdef UNIX
+	gtm_uint16 hash;
+
+	gtmmrhash_128_result(&ctx->hash_state, ctx->total_size, &hash);
+	gtmmrhash_128_bytes(&hash, ctx->digest);
+#	else
 	cvs_MD5Final(ctx->digest, &ctx->md5ctx);
+#	endif
 #	ifndef GTM_USE_128BIT_SRC_CHKSUM
 	GET_ULONG(ctx->checksum, &ctx->digest[0]);
 #	endif
@@ -62,7 +79,7 @@ void rtn_src_chksum_digest(gtm_rtn_src_chksum_ctx *ctx)
 void set_rtnhdr_checksum(rhdtyp *hdr, gtm_rtn_src_chksum_ctx *ctx)
 {
 #	ifdef GTM_USE_128BIT_SRC_CHKSUM
-	memcpy(&hdr->checksum_md5[0], &ctx->digest[0], MD5_DIGEST_LENGTH);
+	memcpy(&hdr->checksum_128[0], &ctx->digest[0], MD5_DIGEST_LENGTH);
 #	else
 	hdr->checksum = ctx->checksum;
 #	endif
@@ -89,7 +106,7 @@ void rtn_src_chksum_buffer(gtm_rtn_src_chksum_ctx *ctx, const void *data, uint4
 
 unsigned char *get_rtnhdr_checksum(rhdtyp *hdr)
 {
-	return &hdr->checksum_md5[0];
+	return &hdr->checksum_128[0];
 }
 
 /*
diff --git a/sr_port/rtn_src_chksum.h b/sr_port/rtn_src_chksum.h
index ff02d43..76f4cc9 100644
--- a/sr_port/rtn_src_chksum.h
+++ b/sr_port/rtn_src_chksum.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -20,12 +20,18 @@
 #include "md5hash.h"
 
 #ifdef UNIX
+# include "mmrhash.h"
 # define GTM_USE_128BIT_SRC_CHKSUM
 #endif
 
 typedef struct
 {
+#	ifdef UNIX
+	hash128_state_t	hash_state;
+	uint4		total_size;
+#	else
 	cvs_MD5_CTX	md5ctx;
+#	endif
 	unsigned char	digest[MD5_DIGEST_LENGTH];
 #	ifndef GTM_USE_128BIT_SRC_CHKSUM
 	uint4		checksum;	/* 32-bit checksum, equals first 4 bytes of digest */
diff --git a/sr_port/s2n.c b/sr_port/s2n.c
index 21d43ed..ece8cda 100644
--- a/sr_port/s2n.c
+++ b/sr_port/s2n.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -32,6 +32,7 @@ char *s2n (mval *u)
 	SETUP_THREADGBL_ACCESS;
 	i = 0;
 	assertpro(MV_DEFINED(u));
+	((mval_b *)u)->sgne = 0;				/* Clear current sign/exponent to contant start value */
 	c = u->str.addr;
 	if (0 == u->str.len)
 	{	/* Substitute pre-converted NULL/0 value */
diff --git a/sr_port/srcline.h b/sr_port/srcline.h
index 04bab4b..9944a04 100644
--- a/sr_port/srcline.h
+++ b/sr_port/srcline.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -35,21 +35,24 @@ typedef struct
 #ifdef GTM_TRIGGER
 /* Macro to determine if a routine name is a trigger name - the answer is yes if
  * the routine name contains a "#" which all triggers do. Args are mstr addr and boolean_t.
+ * Note: If # occurs after 31st byte, then it is treated as a non-trigger routine due to truncation.
  */
-# define IS_TRIGGER_RTN(RTNNAME, RSLT) 												\
-{ 																\
-	unsigned char	*cptr, *cptr_top;											\
-																\
-	if (0 < (RTNNAME)->len)													\
-	{															\
-		for (cptr = (unsigned char *)(RTNNAME)->addr, cptr_top = cptr + (RTNNAME)->len - 1; cptr <= cptr_top; --cptr_top) \
-		{														\
-			if ('#' == *cptr_top)											\
-				break;												\
-		}														\
-		RSLT = !(cptr > cptr_top);											\
-	} else															\
-		RSLT = FALSE;													\
+# define IS_TRIGGER_RTN(RTNNAME, RSLT) 										\
+{ 														\
+	char	*cptr, *cptr_top;										\
+	int	rtnlen;												\
+														\
+	rtnlen = MIN((RTNNAME)->len, MAX_MIDENT_LEN);								\
+	if (0 < rtnlen)												\
+	{													\
+		for (cptr = (RTNNAME)->addr, cptr_top = cptr + rtnlen - 1; cptr <= cptr_top; --cptr_top) 	\
+		{												\
+			if ('#' == *cptr_top)									\
+				break;										\
+		}												\
+		RSLT = !(cptr > cptr_top);									\
+	} else													\
+		RSLT = FALSE;											\
 }
 #else
 # define IS_TRIGGER_RTN(RTNNAME, RSLT) RSLT = FALSE
diff --git a/sr_port/stp_gcol_src.h b/sr_port/stp_gcol_src.h
index 3818ff5..45764c7 100644
--- a/sr_port/stp_gcol_src.h
+++ b/sr_port/stp_gcol_src.h
@@ -60,9 +60,6 @@
 #ifdef GTM_CRYPT
 # include "iormdef.h"
 #endif
-#ifdef USHBIN_SUPPORTED
-# include "relinkctl.h"
-#endif
 
 #ifndef STP_MOVE
 GBLDEF int	indr_stp_low_reclaim_passes = 0;
@@ -106,6 +103,7 @@ GBLREF hash_table_str		*complits_hashtab;
 GBLREF mval			*alias_retarg;
 GTMTRIG_ONLY(GBLREF mval 	dollar_ztwormhole;)
 DEBUG_ONLY(GBLREF   boolean_t	ok_to_UNWIND_in_exit_handling;)
+UNIX_ONLY(GBLREF io_pair	*io_std_device;)
 
 OS_PAGE_SIZE_DECLARE
 
@@ -500,9 +498,6 @@ void stp_gcol(int space_asked)	/* BYPASSOK */
 	glvn_pool_entry		*slot, *top;
 	int			i, n;
 	unsigned char		*old_free;
-#	ifdef USHBIN_SUPPORTED
-	open_relinkctl_sgm	*linkctl;
-#	endif
 #	ifdef GTM_CRYPT
 	d_rm_struct		*rm_ptr;
 #	endif
@@ -582,7 +577,7 @@ void stp_gcol(int space_asked)	/* BYPASSOK */
 	if (((stringpool.base != rts_stringpool.base) || (0 == cache_table.size)))
 	{
 #		ifndef STP_MOVE
-		if (0 != literal_chain.que.fl)
+		if (NULL != literal_chain.que.fl)
 		{	/* If hashtable exists, pull it all from there rather that searching for it twice */
 			if (complits_hashtab && complits_hashtab->base)
 			{
@@ -683,8 +678,16 @@ void stp_gcol(int space_asked)	/* BYPASSOK */
 			if ((IO_ESC != l->dollar_io[0]) && (l->iod->trans_name == l))
 			{
 				MSTR_STPG_ADD(&l->iod->error_handler);
+#				ifdef UNIX
+				/* if this is on UNIX and it is a split $principal, protect
+				 * error_handler defined on the output side
+				 */
+				if ((l->iod->pair.in != l->iod->pair.out)
+				    && (l->iod->pair.out == io_std_device->out))
+					MSTR_STPG_ADD(&l->iod->pair.out->error_handler);
+#				endif
 #				ifdef GTM_CRYPT
-				rm_ptr = (d_rm_struct *)l->iod->dev_sp;
+				rm_ptr = (rm == l->iod->type) ? (d_rm_struct *)l->iod->dev_sp : NULL;
 				if (NULL != rm_ptr)
 				{	/* Protect the IVs and KEYs as needed. */
 					if (rm_ptr->input_encrypted)
@@ -830,7 +833,11 @@ void stp_gcol(int space_asked)	/* BYPASSOK */
 			}
 			MVAL_STPG_ADD(m);
 		}
-		for (sf = frame_pointer; sf < (stack_frame *)stackbase; sf = sf->old_frame_pointer)
+		/* If LINK:RECURSIVE is enabled and the first M frame on the stack is recursively replaced, when it unwinds,
+		 * op_unwind() is going to unlink that version of the routine. We will eventually come here (as stp_move)
+		 * with a zeroed frame pointer so the test below needs to deal with a NULL frame_pointer value.
+		 */
+		for (sf = frame_pointer; (NULL != sf) && (sf < (stack_frame *)stackbase); sf = sf->old_frame_pointer)
 		{	/* Cover temp mvals in use */
 			if (NULL == sf->old_frame_pointer)
 			{	/* If trigger enabled, may need to jump over a base frame */
@@ -885,13 +892,6 @@ void stp_gcol(int space_asked)	/* BYPASSOK */
 				tf = tf->old_tp_frame;
 			}
 		}
-#		ifdef USHBIN_SUPPORTED
-		/* Make sure we keep track of the relinkable directory names */
-		for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
-		{
-			MSTR_STPG_ADD(&linkctl->zro_entry_name);
-		}
-#		endif
 	}
 	space_before_compact = stringpool.top - stringpool.free; /* Available space before compaction */
 	DEBUG_ONLY(blklen = stringpool.free - stringpool.base);
diff --git a/sr_port/svnames.h b/sr_port/svnames.h
index 0cf5e56..f8495c5 100644
--- a/sr_port/svnames.h
+++ b/sr_port/svnames.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -81,6 +81,7 @@ enum
 	SV_ZONLNRLBK,		/* 67 */
 	SV_ZCLOSE,		/* 68 */
 	SV_ZKEY,		/* 69 */
+	SV_ZTDELIM,		/* 70 */
 	SV_NUM_SV,		/* count - should be next to last SV entry just prior to dummy entry below */
 	SV_DUMMY_TO_FORCE_INT = 0x0FFFFFFF	/* to ensure an int on S390 */
 };
diff --git a/sr_port/t_end.c b/sr_port/t_end.c
index 45d5a2d..5df1c0d 100644
--- a/sr_port/t_end.c
+++ b/sr_port/t_end.c
@@ -270,11 +270,13 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
 	 * (b) DSE CRIT -SEIZE (and any command that follows it), DSE CHANGE -BLOCK, DSE ALL -SEIZE (and any command that follows)
 	 *	and DSE MAPS -RESTORE_ALL. Since we cannot distinguish between different DSE qualifiers, we use IS_DSE_IMAGE.
 	 * (c) gvcst_redo_root_search in the final retry.
+	 * (d) MUPIP TRIGGER -UPGRADE which is a TP transaction but it could do non-TP as part of gvcst_bmp_mark_free at the end.
 	 *
 	 * Since we don't expect hold_onto_crit to be set by any other utility/function, the below assert is valid and is intended
 	 * to catch cases where the field is inadvertently set to TRUE.
 	 */
-	assert(!csa->hold_onto_crit || IS_DSE_IMAGE UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_gvcst_redo_root_search)));
+	assert(!csa->hold_onto_crit || IS_DSE_IMAGE
+		UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_gvcst_redo_root_search) || TREF(in_trigger_upgrade)));
 	assert(cs_data == csd);
 	assert((t_tries < CDB_STAGNATE) || csa->now_crit);
 	assert(!dollar_tlevel);
diff --git a/sr_port/t_end_sysops.c b/sr_port/t_end_sysops.c
index fb44ef8..fdf3400 100644
--- a/sr_port/t_end_sysops.c
+++ b/sr_port/t_end_sysops.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2007, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2007, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -1204,9 +1204,10 @@ enum cdb_sc	bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect
 	{	/* either it is a non-local bit-map or we are in dse_maps or MUPIP RECOVER writing an AIMG record */
 		assert((0 != (blkid & (BLKS_PER_LMAP - 1))) || write_after_image);
 		/* we should NOT be in crit for phase2 except dse_maps/dse_chng_bhead OR if cse has a non-zero recompute list. The
-		 * only exception to this is ONLINE ROLLBACK which holds crit for the entire duration
+		 * only exception to this is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
 		 */
-		assert(!csa->now_crit || cs->recompute_list_head || dse_running UNIX_ONLY(|| jgbl.onlnrlbk));
+		assert(!csa->now_crit || cs->recompute_list_head || dse_running
+			UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
 		if (FALSE == cs->done)
 		{	/* if the current block has not been built (from being referenced in TP) */
 			if (NULL != cs->new_buff)
diff --git a/sr_port/tab_gvstats_rec.h b/sr_port/tab_gvstats_rec.h
index 1c58456..274dd30 100644
--- a/sr_port/tab_gvstats_rec.h
+++ b/sr_port/tab_gvstats_rec.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2008, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2008, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -64,3 +64,13 @@ TAB_GVSTATS_REC(n_jrec_epoch_idle    , "JRI", "# of Idle epoch Journal Records
 TAB_GVSTATS_REC(n_jrec_other         , "JRO", "# of Other Journal Records            ")
 TAB_GVSTATS_REC(n_jnl_extends        , "JEX", "# of Journal file EXtensions          ")
 TAB_GVSTATS_REC(n_db_extends         , "DEX", "# of Database file EXtensions         ")
+#ifdef UNIX
+TAB_GVSTATS_REC(n_crit_success       , "CAT", "# of crit acquired total successes    ")
+TAB_GVSTATS_REC(n_crits_in_epch      , "CFE", "# of attempts in CFT caused by epochs ")
+TAB_GVSTATS_REC(sq_crit_failed       , "CFS", "sum squares grab crit failed          ")
+TAB_GVSTATS_REC(n_crit_failed        , "CFT", "# of grab crit failures               ")
+TAB_GVSTATS_REC(sq_crit_que_slps     , "CQS", "sum squares grab crit queued sleeps   ")
+TAB_GVSTATS_REC(n_crit_que_slps      , "CQT", "# of grab crit queued sleeps          ")
+TAB_GVSTATS_REC(sq_crit_yields       , "CYS", "sum squares grab crit yields          ")
+TAB_GVSTATS_REC(n_crit_yields        , "CYT", "# of grab crit yields                 ")
+#endif
diff --git a/sr_port/tp.h b/sr_port/tp.h
index 1875bf8..9b0f506 100644
--- a/sr_port/tp.h
+++ b/sr_port/tp.h
@@ -84,6 +84,9 @@ typedef struct global_tlvl_info_struct
 #	endif
 	struct ua_list	*curr_ua;		/* points to global variable curr_ua at start of this transaction */
 	char		*upd_array_ptr;		/* points to global variable update_array_ptr at start of this transaction */
+#	ifdef GTM_TRIGGER
+	int		ztrigbuffLen;		/* copy of TREF(ztrigbuffLen) at start of this transaction */
+#	endif
 } global_tlvl_info;
 
 /* A note on the buddy lists used in sgm_info structure,
@@ -709,7 +712,7 @@ typedef struct trans_restart_hist_struct
 				{	/* TROLLBACK(0) or TRESTART. Reset db_dztrigger_cycle to 0 since we are going to start 	\
 					 * a new transaction. But, we want to ensure that the new transaction re-reads triggers	\
 					 * since any gvt which updated its gvt_trigger in this transaction will be stale as	\
-					 * they never got committed.								\
+					 * they never got committed. We will later ensure csa->db_dztrigger_cycle is non-zero.	\
 					 */											\
 					gvnh->db_dztrigger_cycle = 0;								\
 					gvnh->db_trigger_cycle = 0;								\
@@ -753,10 +756,13 @@ typedef struct trans_restart_hist_struct
 		} else if (!COMMIT)												\
 		{	/* This is either a complete rollback or a restart. In either case, set csa->incr_db_trigger_cycle 	\
 			 * to FALSE for all csa referenced in this transaction as they are anyways not going to be committed.	\
+			 * Based on this though, set csa->db_dztrigger_cycle to a non-zero value this way we ensure		\
+			 * triggers are forced to be re-read on the restart/rollback so any cached stale trigger state from	\
+			 * the current failed try is thrown away.								\
 			 */													\
 			for (si = first_sgm_info; NULL != si; si = si->next_sgm_info)						\
 			{													\
-				si->tp_csa->db_dztrigger_cycle = 0;								\
+				si->tp_csa->db_dztrigger_cycle = si->tp_csa->incr_db_trigger_cycle ? 1 : 0;			\
 				si->tp_csa->incr_db_trigger_cycle = FALSE;							\
 			}													\
 		}														\
@@ -794,17 +800,19 @@ typedef struct trans_restart_hist_struct
 }
 # ifdef DEBUG
 #  define TP_ASSERT_ZTRIGGER_CYCLE_RESET										\
-{	/* At the end of a transaction (either because of trestart, complete trollback or tcommit) ensure that 		\
-	 * csa->db_dztrigger_cycle is reset to zero. It's okay not to check if all gvt updated in this transaction	\
-	 * also has gvt->db_dztrigger_cycle set back to zero because if they don't there are other asserts that 	\
-	 * will trip in the subsequent transactions									\
+{	/* At the end of a transaction commit ensure that csa->db_dztrigger_cycle is reset to zero.			\
+	 * In the case of trestart and/or rollback, this value could be 1 if $ztrigger activity happened in		\
+	 * the failed try. Because of this it is also possible the value could be 1 after a commit (that is preceded	\
+	 * by a restart). Assert this.											\
+	 * It's okay not to check if all gvt updated in this transaction also has gvt->db_dztrigger_cycle set		\
+	 * back to zero because if they don't there are other asserts that will trip in the subsequent transactions.	\
 	 */														\
 	GBLREF	sgm_info	*first_sgm_info;									\
 															\
 	sgm_info		*si;											\
 															\
 	for (si = first_sgm_info; NULL != si; si = si->next_sgm_info)							\
-		assert(0 == si->tp_csa->db_dztrigger_cycle);								\
+		assert((0 == si->tp_csa->db_dztrigger_cycle) || (1 == si->tp_csa->db_dztrigger_cycle));			\
 }
 # else
 #  define TP_ASSERT_ZTRIGGER_CYCLE_RESET
diff --git a/sr_port/tp_clean_up.c b/sr_port/tp_clean_up.c
index 140aae5..bf3c459 100644
--- a/sr_port/tp_clean_up.c
+++ b/sr_port/tp_clean_up.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -35,6 +35,7 @@
 #ifdef GTM_TRIGGER
 #include <rtnhdr.h>
 #include "gv_trigger.h"		/* for TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */
+#include "util.h"		/* for TP_ZTRIGBUFF_PRINT macro */
 #endif
 
 GBLREF	sgmnt_data_ptr_t	cs_data;
@@ -190,7 +191,8 @@ void	tp_clean_up(boolean_t rollback_flag)
 									 */
 		}
 		GTMTRIG_ONLY(assert(!TREF(gvt_triggers_read_this_tn));)
-		GTMTRIG_ONLY(TP_ASSERT_ZTRIGGER_CYCLE_RESET;) /* for all regions, we better have csa->db_dztrigger_cycle = 0*/
+		/* Assert that for all regions, we have csa->db_dztrigger_cycle = 0 or 1 (based on commit/restart/rollback) */
+		GTMTRIG_ONLY(TP_ASSERT_ZTRIGGER_CYCLE_RESET;)
 		for (si = first_sgm_info;  si != NULL;  si = next_si)
 		{
 			TP_TEND_CHANGE_REG(si);
@@ -432,9 +434,10 @@ void	tp_clean_up(boolean_t rollback_flag)
 	sgm_info_ptr = NULL;
 	first_sgm_info = NULL;
 	/* ensure that we don't have crit on any region at the end of a TP transaction (be it GT.M or MUPIP). The only exception
-	 * is ONLINE ROLLBACK which holds crit for the entire duration
+	 * is ONLINE ROLLBACK or MUPIP TRIGGER -UPGRADE which holds crit for the entire duration
 	 */
-	assert((CDB_STAGNATE == t_tries) || (0 == have_crit(CRIT_HAVE_ANY_REG)) UNIX_ONLY(|| jgbl.onlnrlbk));
+	assert((CDB_STAGNATE == t_tries) || (0 == have_crit(CRIT_HAVE_ANY_REG))
+						UNIX_ONLY(|| jgbl.onlnrlbk || TREF(in_trigger_upgrade)));
 	/* Now that this transaction try is done (need to start a fresh try in case of a restart; in case of commit the entire
 	 * transaction is done) ensure first_tp_si_by_ftok is NULL at end of tp_clean_up as this field is relied upon by
 	 * secshr_db_clnup and t_commit_cleanup to determine if we have an ongoing transaction. In case of a successfully
@@ -445,4 +448,11 @@ void	tp_clean_up(boolean_t rollback_flag)
 	assert(rollback_flag || (NULL == first_tp_si_by_ftok));
 	first_tp_si_by_ftok = NULL;
 	ENABLE_INTERRUPTS(INTRPT_IN_TP_CLEAN_UP);	/* check if any MUPIP STOP/signals were deferred while in this function */
+#	ifdef GTM_TRIGGER
+	if (!rollback_flag)
+	{
+		TP_ZTRIGBUFF_PRINT; /* TP is committed so print $ZTRIGGER/MUPIP-TRIGGER activity output in this tn */
+	} else
+		TREF(ztrigbuffLen) = 0;
+#	endif
 }
diff --git a/sr_port/tp_incr_clean_up.c b/sr_port/tp_incr_clean_up.c
index febf9d5..4d03ab0 100644
--- a/sr_port/tp_incr_clean_up.c
+++ b/sr_port/tp_incr_clean_up.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -260,9 +260,10 @@ void rollbk_gbl_tlvl_info(uint4 newlevel)
 	sgmnt_addrs		*old_csa, *tmp_next_csa;
 	ua_list			*ua_ptr;
 	DEBUG_ONLY(uint4	dbg_upd_array_size;)
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	old_csa = jnl_fence_ctl.fence_list;
-
 	for (prev_gtli = NULL, gtli = global_tlvl_info_head; gtli; gtli = gtli->next_global_tlvl_info)
 	{
 		if (newlevel < gtli->t_level)
@@ -284,6 +285,7 @@ void rollbk_gbl_tlvl_info(uint4 newlevel)
 		assert(NULL != gtli->curr_ua);
 		curr_ua = (ua_list *)(gtli->curr_ua);
 		update_array_ptr = gtli->upd_array_ptr;
+		GTMTRIG_ONLY(TREF(ztrigbuffLen) = gtli->ztrigbuffLen;)
 	} else
 	{
 		jnl_fence_ctl.fence_list = JNL_FENCE_LIST_END;
diff --git a/sr_port/tp_tend.c b/sr_port/tp_tend.c
index 67c9958..95ba835 100644
--- a/sr_port/tp_tend.c
+++ b/sr_port/tp_tend.c
@@ -109,6 +109,7 @@ GBLREF	jnl_fence_control	jnl_fence_ctl;
 GBLREF	jnlpool_addrs		jnlpool;
 GBLREF	jnlpool_ctl_ptr_t	jnlpool_ctl, temp_jnlpool_ctl;
 GBLREF	boolean_t		is_updproc;
+GBLREF	boolean_t		is_replicator;
 GBLREF	seq_num			seq_num_zero;
 GBLREF	seq_num			seq_num_one;
 GBLREF	int			gv_fillfactor;
@@ -152,7 +153,7 @@ error_def(ERR_TEXT);
 	GBLREF	boolean_t		is_updproc;						\
 	UNIX_ONLY(GBLREF recvpool_addrs	recvpool;)						\
 												\
-	if (REPL_ALLOWED(CSA))									\
+	if (REPL_ALLOWED(CSA) && is_replicator)							\
 	{											\
 		assert(CSA->hdr->reg_seqno < TJPL->jnl_seqno);					\
 		CSA->hdr->reg_seqno = TJPL->jnl_seqno;						\
@@ -320,10 +321,11 @@ boolean_t	tp_tend()
 		csd = cs_data;
 		cnl = csa->nl;
 		is_mm = (dba_mm == csd->acc_meth);
-		UNIX_ONLY(
-			assert(!csa->hold_onto_crit || jgbl.onlnrlbk); /* In TP, hold_onto_crit is set ONLY by online rollback */
-			assert(!jgbl.onlnrlbk || (csa->hold_onto_crit && csa->now_crit));
-		)
+#		ifdef UNIX
+		assert(!csa->hold_onto_crit || jgbl.onlnrlbk || TREF(in_trigger_upgrade));
+		assert(!jgbl.onlnrlbk || (csa->hold_onto_crit && csa->now_crit));
+		assert(!TREF(in_trigger_upgrade) || (csa->hold_onto_crit && csa->now_crit));
+#		endif
 		si = (sgm_info *)(csa->sgm_info_ptr);
 		sgm_info_ptr = si;
 		*prev_tp_si_by_ftok = si;
@@ -424,7 +426,8 @@ boolean_t	tp_tend()
 			{
 				assert(JNL_ENABLED(csa) || REPL_WAS_ENABLED(csa));
 				replication = TRUE;
-				repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
+				if (is_replicator)
+					repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
 				jnl_participants++;
 			} else if (JNL_ENABLED(csa))
 			{
@@ -451,9 +454,17 @@ boolean_t	tp_tend()
 			SET_GBL_JREC_TIME;	/* initializes jgbl.gbl_jrec_time */
 		assert(jgbl.gbl_jrec_time);
 		/* If any one DB that we are updating has replication turned on and another has only journaling, issue error */
-		if (replication && yes_jnl_no_repl)
-			rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2,
-					DB_LEN_STR(save_gv_cur_region));
+		if (replication)
+		{
+			if (yes_jnl_no_repl)
+				rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2,
+						DB_LEN_STR(save_gv_cur_region));
+			/* If caller does NOT want this update to be replicated, turn "replication" local variable off.
+			 * The only such caller known at this time is "trigger_upgrade" - 2014/05/02.
+			 */
+			if (!is_replicator)
+				replication = FALSE;
+		}
 	}
 	if (!do_validation)
 	{
@@ -1778,8 +1789,8 @@ boolean_t	tp_tend()
 			rel_lock(jnlpool.jnlpool_dummy_reg);
 	}
 	/* Check that we DONT own crit on ANY region. The only exception is online mupip journal rollback/recovery
-	 * which holds crit for the entire process lifetime. */
-	assert(UNIX_ONLY(jgbl.onlnrlbk || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
+	 * or MUPIP TRIGGER -UPGRADE which holds crit for the entire process lifetime. */
+	assert(UNIX_ONLY(jgbl.onlnrlbk || TREF(in_trigger_upgrade) || ) (0 == have_crit(CRIT_HAVE_ANY_REG)));
 	/* the following section is the actual commitment of the changes in the database (phase2 for BG) */
 	for (si = first_tp_si_by_ftok;  (NULL != si); si = si->next_tp_si_by_ftok)
 	{
diff --git a/sr_port/unw_mv_ent.c b/sr_port/unw_mv_ent.c
index 8430a07..86f898f 100644
--- a/sr_port/unw_mv_ent.c
+++ b/sr_port/unw_mv_ent.c
@@ -75,6 +75,7 @@ GBLREF lv_xnew_var		*xnewvar_anchor;
 #ifdef GTM_TRIGGER
 GBLREF mstr			*dollar_ztname;
 GBLREF mval			*dollar_ztdata;
+GBLREF mval			*dollar_ztdelim;
 GBLREF mval			*dollar_ztoldval;
 GBLREF mval			*dollar_ztriggerop;
 GBLREF mval			*dollar_ztupdate;
@@ -443,6 +444,7 @@ void unw_mv_ent(mv_stent *mv_st_ent)
 			dollar_ztvalue = mv_st_ent->mv_st_cont.mvs_trigr.ztvalue_save;
 			dollar_ztname = mv_st_ent->mv_st_cont.mvs_trigr.ztname_save;
 			dollar_ztdata = mv_st_ent->mv_st_cont.mvs_trigr.ztdata_save;
+			dollar_ztdelim = mv_st_ent->mv_st_cont.mvs_trigr.ztdelim_save;
 			dollar_ztoldval = mv_st_ent->mv_st_cont.mvs_trigr.ztoldval_save;
 			dollar_ztriggerop = mv_st_ent->mv_st_cont.mvs_trigr.ztriggerop_save;
 			dollar_ztupdate = mv_st_ent->mv_st_cont.mvs_trigr.ztupdate_save;
@@ -465,13 +467,15 @@ void unw_mv_ent(mv_stent *mv_st_ent)
 			ctxt = mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save;
 			/* same assert as in gtm_trigger.c */
 			assert(((0 == gtm_trigger_depth)
-				&& (((ch_at_trigger_init == ctxt->ch)
-				     || ((ch_at_trigger_init == (ctxt - 1)->ch)
-					 && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch))))))
-			       || ((0 < gtm_trigger_depth)
-				   && (((&mdb_condition_handler == ctxt->ch)
-					|| ((&mdb_condition_handler == (ctxt - 1)->ch)
-					    && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)))))));
+					&& (((ch_at_trigger_init == ctxt->ch)
+						|| ((ch_at_trigger_init == (ctxt - 1)->ch)
+							&& ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+								|| (&gvcst_spr_kill_ch == ctxt->ch))))))
+				|| ((0 < gtm_trigger_depth)
+					&& (((&mdb_condition_handler == ctxt->ch)
+						|| ((&mdb_condition_handler == (ctxt - 1)->ch)
+							&& ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+								|| (&gvcst_spr_kill_ch == ctxt->ch)))))));
 			active_ch = ctxt;
 			ctxt->ch_active = FALSE;
 			if (tp_timeout_deferred && !((0 < dollar_ecode.index) && (ETRAP_IN_EFFECT))
diff --git a/sr_port/unw_retarg.c b/sr_port/unw_retarg.c
index 04d8559..86afd61 100644
--- a/sr_port/unw_retarg.c
+++ b/sr_port/unw_retarg.c
@@ -35,17 +35,24 @@
 #include "get_ret_targ.h"
 #include "opcode.h"
 #include "glvn_pool.h"
+#include "zr_unlink_rtn.h"
+#include "tp_timeout.h"
 
-GBLREF	void		(*unw_prof_frame_ptr)(void);
-GBLREF	stack_frame	*frame_pointer, *zyerr_frame;
-GBLREF	unsigned char	*msp,*stackbase,*stacktop;
-GBLREF	mv_stent	*mv_chain;
-GBLREF	tp_frame	*tp_pointer;
-GBLREF	boolean_t	is_tracing_on;
-GBLREF	symval		*curr_symval;
-GBLREF	mval		*alias_retarg;
-GBLREF	boolean_t	dollar_truth;
-GBLREF	boolean_t	dollar_zquit_anyway;
+GBLREF	void			(*unw_prof_frame_ptr)(void);
+GBLREF	stack_frame		*frame_pointer, *zyerr_frame;
+GBLREF	unsigned char		*msp, *stackbase, *stacktop;
+GBLREF	mv_stent		*mv_chain;
+GBLREF	tp_frame		*tp_pointer;
+GBLREF	boolean_t		is_tracing_on;
+GBLREF	symval			*curr_symval;
+GBLREF	mval			*alias_retarg;
+GBLREF	boolean_t		dollar_truth;
+GBLREF	boolean_t		dollar_zquit_anyway;
+GBLREF	boolean_t		dollar_zininterrupt;
+GBLREF	mval			dollar_ztrap;
+GBLREF	boolean_t		ztrap_explicit_null;
+GBLREF	boolean_t		tp_timeout_deferred;
+GBLREF	dollar_ecode_type	dollar_ecode;
 
 LITREF	mval 		literal_null;
 
@@ -57,9 +64,10 @@ error_def(ERR_TPQUIT);
 /* This has to be maintained in parallel with op_unwind(), the unwind without a return argument (intrinsic quit) routine. */
 int unw_retarg(mval *src, boolean_t alias_return)
 {
+	rhdtyp		*rtnhdr;
 	mval		ret_value, *trg;
 	boolean_t	got_ret_target;
-	stack_frame	*prevfp;
+	stack_frame	*prevfp, *fp;
 	lv_val		*srclv, *srclvc, *base_lv;
 	symval		*symlv, *symlvc;
 	int4		srcsymvlvl;
@@ -165,6 +173,7 @@ int unw_retarg(mval *src, boolean_t alias_return)
 	msp = (unsigned char *)frame_pointer + SIZEOF(stack_frame);
 	DRAIN_GLVN_POOL_IF_NEEDED;
 	PARM_ACT_UNSTACK_IF_NEEDED;
+	USHBIN_ONLY(rtnhdr = frame_pointer->rvector);	/* Save rtnhdr for cleanup call below */
 	frame_pointer = frame_pointer->old_frame_pointer;
 	DBGEHND((stderr, "unw_retarg: Stack frame 0x"lvaddr" unwound - frame 0x"lvaddr" now current - New msp: 0x"lvaddr"\n",
 		 prevfp, frame_pointer, msp));
@@ -177,5 +186,12 @@ int unw_retarg(mval *src, boolean_t alias_return)
 	if (!dollar_zquit_anyway || trg)
 		trg->mvtype |= MV_RETARG;
 	assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
+	USHBIN_ONLY(CLEANUP_COPIED_RECURSIVE_RTN(rtnhdr));
+	/* We just unwound a frame. May have been either a zintrupt frame and/or may have unwound a NEW'd ZTRAP or even cleared
+	 * our error state. If we have a deferred timeout and none of the deferral conditions are anymore in effect, release
+	 * the hounds.
+	 */
+	if (tp_timeout_deferred UNIX_ONLY(&& !dollar_zininterrupt) && ((0 == dollar_ecode.index) || !(ETRAP_IN_EFFECT)))
+		tptimeout_set(0);
 	return 0;
 }
diff --git a/sr_port/updhelper_reader.c b/sr_port/updhelper_reader.c
index cb43a0d..8fd7017 100644
--- a/sr_port/updhelper_reader.c
+++ b/sr_port/updhelper_reader.c
@@ -109,7 +109,6 @@ GBLREF 	sgmnt_data_ptr_t 	cs_data;
 GBLREF  uint4                   image_count;
 #endif
 GBLREF boolean_t		disk_blk_read;
-LITREF	mval			literal_hasht;
 static	uint4			last_pre_read_offset;
 
 error_def(ERR_DBCCERR);
diff --git a/sr_port/updproc.c b/sr_port/updproc.c
index adfa376..ce5a1da 100644
--- a/sr_port/updproc.c
+++ b/sr_port/updproc.c
@@ -62,6 +62,7 @@
 #ifdef GTM_TRIGGER
 #include <rtnhdr.h>			/* for rtn_tabent in gv_trigger.h */
 #include "gv_trigger.h"
+# include "gtm_trigger.h"
 #include "targ_alloc.h"
 #include "trigger.h"
 #include "hashtab_str.h"
@@ -150,16 +151,16 @@ GBLREF	int			tprestart_state;        /* When triggers restart, multiple states p
 GBLREF	dollar_ecode_type	dollar_ecode;		/* structure containing $ECODE related information */
 GBLREF	mval			dollar_ztwormhole;
 GBLREF	boolean_t		dollar_ztrigger_invoked;
+GBLREF	stack_frame		*frame_pointer;	/* needed by TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND macro */
 #endif
 GBLREF	boolean_t		skip_dbtriggers;
 GBLREF	gv_namehead		*gv_target;
 GBLREF	boolean_t		gv_play_duplicate_kills;
 #ifdef UNIX
-GBLREF		int4			strm_index;
-STATICDEF	boolean_t		set_onln_rlbk_flg;
+GBLREF		int4		strm_index;
+STATICDEF	boolean_t	set_onln_rlbk_flg;
 #endif
 
-LITREF	mval			literal_hasht;
 static	boolean_t		updproc_continue = TRUE;
 
 error_def(ERR_GBLOFLOW);
@@ -265,9 +266,12 @@ error_def(ERR_UPDREPLSTATEOFF);
 
 CONDITION_HANDLER(updproc_ch)
 {
-	int		rc;
-	unsigned char	seq_num_str[32], *seq_num_ptr;
-	unsigned char	seq_num_strx[32], *seq_num_ptrx;
+	int			rc;
+	unsigned char		seq_num_str[32], *seq_num_ptr;
+	unsigned char		seq_num_strx[32], *seq_num_ptrx;
+#	ifdef GTM_TRIGGER
+	condition_handler	*save_active_ch;
+#	endif
 
 	START_CH(TRUE);
 	if ((int)ERR_TPRETRY == SIGNAL)
@@ -287,6 +291,24 @@ CONDITION_HANDLER(updproc_ch)
 		if (first_sgm_info GTMTRIG_ONLY( || (TPRESTART_STATE_NORMAL != tprestart_state)))
 		{
 			VMS_ONLY(assert(FALSE == tp_restart_fail_sig_used);)
+#			ifdef GTM_TRIGGER
+			/* Note: Below GTM_TRIGGER-only code is similar to mdb_condition_handler. But unlike there,
+			 * where MUM_TSTART is done inside the condition handler to transfer control, we do an UNWIND
+			 * here in updproc_ch. The UNWIND macro does an active_ch++ (to balance out the active_ch-- done
+			 * by START_CH done at the entry of every condition handler). We want to preserve active_ch in
+			 * the state that UNWIND expects. But the macro call done below calls gtm_trigger_fini which in
+			 * turn calls unw_mv_ent which could modify active_ch as part of popping MVST_TRIGR. Work around
+			 * that by saving and restoring active_ch after the macro call so UNWIND is fine. But what this
+			 * means is that for a short code window (from when unw_mv_ent sets active_ch to when we reset it
+			 * after the macro call below), active_ch would be incorrectly set to updproc_ch (instead of
+			 * util_base_ch which START_CH would have set it to above). But that is okay since we dont expect
+			 * any TPRETRY errors in this short window and updproc_ch would anyways transfer control to
+			 * util_base_ch (through NEXTCH) for all non-TPRETRY errors.
+			 */
+			save_active_ch = active_ch;
+			TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND;
+			active_ch = save_active_ch;
+#			endif
 			rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS); /* any nested errors will set SIGNAL accordingly */
 			assert(0 == rc);			/* No partials restarts can happen at this final level */
 			GTMTRIG_ONLY(assert(TPRESTART_STATE_NORMAL == tprestart_state));
@@ -1382,7 +1404,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
 						assert(NULL != tmpcsa);
 						rts_error_csa(CSA_ARG(tmpcsa) VARLSTCNT(10) ERR_REC2BIG, 4,
 							VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) val_mv.str.len,
-							(int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region),
+							(int4)(tmpcsa->region)->max_rec_size, REG_LEN_STR(tmpcsa->region),
 							ERR_GVIS, 2, end - buff, buff);
 						break;
 				}
diff --git a/sr_port/updproc.h b/sr_port/updproc.h
index 5fd830b..9dc2fe8 100644
--- a/sr_port/updproc.h
+++ b/sr_port/updproc.h
@@ -37,49 +37,10 @@ enum upd_bad_trans_type
 #define	UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG)	GV_BIND_NAME_AND_ROOT_SEARCH(GD_HEADER, &GVNAME, GVNH_REG)
 
 #ifdef GTM_TRIGGER
-#define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG)				\
-{													\
-	char			*tr_ptr;								\
-	mname_entry		gvname1;								\
-	int			tr_len;									\
-	sgmnt_addrs		*csa;									\
-													\
-	GBLREF boolean_t	dollar_ztrigger_invoked;						\
-													\
-	if (IS_MNAME_HASHT_GBLNAME(GVNAME.var_name))							\
-	{	/* gbl is ^#t. In this case, do special processing. Look at the first subscript and	\
-		 * bind to the region mapped to by that global name (not ^#t). Also since V62 will	\
-		 * never receive ^#t records from V62 source (it will receive TLGTRIG/ULGTRIG logical	\
-		 * journal records only) assert accordingly.						\
-		 */											\
-		assert(V24_JNL_VER > gtmrecv_local->remote_side.jnl_ver);				\
-		tr_ptr = KEY;			/* Skip to the first subscript */			\
-		tr_len = STRLEN(KEY);		/* Only want length to first 0, not entire length */	\
-		assert(tr_len < KEYLEN);	/* If ^#t, there has to be a subscript */		\
-		tr_ptr += tr_len;									\
-		assert((KEY_DELIMITER == *tr_ptr) && ((char)STR_SUB_PREFIX == *(tr_ptr + 1)));		\
-		tr_ptr += 2;				/* Skip the 0x00 and 0xFF */			\
-		assert((HASHT_GBL_CHAR1 == *tr_ptr) || ('%' == *tr_ptr) || (ISALPHA_ASCII(*tr_ptr)));	\
-		if (HASHT_GBL_CHAR1 != *tr_ptr)								\
-		{											\
-			gvname1.var_name.addr = tr_ptr;							\
-			gvname1.var_name.len = STRLEN(tr_ptr);						\
-			COMPUTE_HASH_MNAME(&gvname1);							\
-			GV_BIND_NAME_ONLY(GD_HEADER, &gvname1, GVNH_REG);				\
-			csa = cs_addrs;									\
-			SET_GVTARGET_TO_HASHT_GBL(csa);							\
-			dollar_ztrigger_invoked = TRUE;							\
-			csa->incr_db_trigger_cycle = TRUE;						\
-			csa->db_dztrigger_cycle++;							\
-		} else											\
-		{											\
-			SWITCH_TO_DEFAULT_REGION;							\
-			/* Special case for ^#t. Set GVNH_REG to NULL. Caller needs to check this */	\
-			GVNH_REG = NULL;								\
-		}											\
-		INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;							\
-	} else												\
-		UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG);						\
+#define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG)	\
+{										\
+	assert(!IS_MNAME_HASHT_GBLNAME(GVNAME.var_name));			\
+	UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG);				\
 }
 #else
 #define UPD_GV_BIND_NAME_APPROPRIATE(GD_HEADER, GVNAME, KEY, KEYLEN, GVNH_REG)	UPD_GV_BIND_NAME(GD_HEADER, GVNAME, GVNH_REG)
diff --git a/sr_port/updproc_get_gblname.c b/sr_port/updproc_get_gblname.c
index b75cab0..b0a4a5b 100644
--- a/sr_port/updproc_get_gblname.c
+++ b/sr_port/updproc_get_gblname.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -32,14 +32,16 @@
 #include "updproc_get_gblname.h"
 #include "min_max.h"
 #include "hashtab_mname.h"
+#include "toktyp.h"		/* Needed for "valid_mname.h" */
+#include "valid_mname.h"
 
 /* This routine validates the key from journal record copying to memory pointed updproc_get_gblname
  * "gvname" is an mname_entry pointing to the global name (to be used for gv_bind_name) is set here.
  */
 enum upd_bad_trans_type updproc_get_gblname(char *src_ptr, int key_len, char *gv_mname, mname_entry *gvname)
 {
-	char			*dest_ptr;
-	int			cplen;
+	char		*dest_ptr;
+	int		cplen;
 
 	cplen = MIN(MAX_MIDENT_LEN + 1, key_len);	/* +1 to consider null */
 	dest_ptr = (char *)gv_mname;
@@ -53,6 +55,11 @@ enum upd_bad_trans_type updproc_get_gblname(char *src_ptr, int key_len, char *gv
 		return upd_bad_mname_size;
 	gvname->var_name.addr = (char *)gv_mname;
 	gvname->var_name.len = INTCAST(dest_ptr - 1 - (char *)gv_mname);
+	/* We have already checked for global name length. Now check for global name contents */
+	if (!valid_mname(&gvname->var_name))
+		return upd_bad_mname_size;	/* caller currently only cares good or bad so overload existing error
+						 * even if not entirely accurate.
+						 */
 	COMPUTE_HASH_MNAME(gvname);
 	return upd_good_record;
 }
diff --git a/sr_port/util.h b/sr_port/util.h
index fa8ce82..226567d 100644
--- a/sr_port/util.h
+++ b/sr_port/util.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -48,9 +48,10 @@ void util_log_open(char *filename, uint4 len);
 void util_out_write(unsigned char *addr, unsigned int len);
 #else /* UNIX */
 #include "gtm_stdio.h"		/* for FILE * */
-void util_in_open(void *);
-char *util_input(char *buffer, int buffersize, FILE *fp, boolean_t remove_leading_spaces);
-void util_out_print_gtmio(caddr_t message, int flush, ...);
+void		util_in_open(void *);
+char		*util_input(char *buffer, int buffersize, FILE *fp, boolean_t remove_leading_spaces);
+void		util_out_print_gtmio(caddr_t message, int flush, ...);
+boolean_t	util_out_save(char *dst, int *dstlen_ptr);
 #ifdef DEBUG
 void		util_out_syslog_dump(void);
 
@@ -75,7 +76,7 @@ void		util_out_syslog_dump(void);
 		(TREF(util_outbuff_ptr)) += OUT_BUFF_SIZE;				\
 		VAR_COPY(VA_LIST_SAVE_PTR, TREF(last_va_list_ptr));			\
 		UTIL_OUT_SAVE_PTR = TREF(util_outptr);					\
-		TREF(util_outptr) = NULL;						\
+		TREF(util_outptr) = TREF(util_outbuff_ptr);				\
 		COPY_SAVED = TRUE;							\
 	} else										\
 		assert(FALSE);								\
@@ -106,6 +107,20 @@ void		util_out_syslog_dump(void);
 #define HEX8		8
 #define HEX16		16
 
+#define	TP_ZTRIGBUFF_PRINT				\
+{							\
+	DCL_THREADGBL_ACCESS;				\
+							\
+	SETUP_THREADGBL_ACCESS;				\
+	if (TREF(ztrigbuffLen))				\
+	{						\
+		tp_ztrigbuff_print();			\
+		TREF(ztrigbuffLen) = 0;			\
+	}						\
+}
+
+void tp_ztrigbuff_print(void);
+
 void util_exit_handler(void);
 void util_out_close(void);
 void util_out_send_oper(char *addr, unsigned int len);
diff --git a/sr_port/verify_queue.c b/sr_port/verify_queue.c
index fb29602..0a0ad96 100644
--- a/sr_port/verify_queue.c
+++ b/sr_port/verify_queue.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2005 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -10,19 +10,12 @@
  ****************************************************************/
 
 /* Routines to verify a simple double-linked queue.
-
-   If we fail any of these tests, we will gtmassert in case a call to
-   this routine is made from "pro" code. No messages are produced by
-   this code since they would be useful only in the context of the
-   dumped data and would scare the hell out of the user anyway.
-
-   Two versions of this test are supplied. The first will lock the queue
-   header first. The second assumes the queue is already locked.
-
-   Most(All?) calls to this routine are compiled in by specifying the compile
-   flag DEBUG_QUEUE.
-
-*/
+ *
+ * If we fail any of these tests in pro code, we gtmassert.
+ * This code produces no messages because they would be useful only in the context of the dumped data and would scare the user.
+ * We have two versions of this test. The first locks the queue header. The second assumes the queue is already locked.
+ * Most calls to this routine are compiled in by specifying the compile flag DEBUG_QUEUE.
+ */
 
 #include "mdef.h"
 
@@ -54,16 +47,14 @@ GBLREF	volatile int4	fast_lock_count;
 GBLREF	pid_t		process_id;
 VMS_ONLY(GBLREF	uint4	image_count;)	/* Needed for GET/RELEASE_SWAPLOCK */
 
-void verify_queue_lock(que_head_ptr_t qhdr)
+gtm_uint64_t verify_queue_lock(que_head_ptr_t qhdr)
 {
 	que_ent_ptr_t	qe, last_qe;
-	int		i, k;
-	boolean_t		got_lock;
+	gtm_uint64_t	i, k;
+	boolean_t	got_lock;
 
 	++fast_lock_count;
-
-	/* Before we can play with the queue, we have to lock it
-	   to prevent it from being changed out from underneath us */
+	/* Before running this queue, must lock it to prevent it from being changed during our run */
 	for (got_lock = FALSE, k = 0; k < QI_STARVATION; ++k)
 	{
 		for (i = 0; got_lock == FALSE && i < QI_RETRY; ++i)
@@ -73,48 +64,27 @@ void verify_queue_lock(que_head_ptr_t qhdr)
 		if (0 != k)
 			wcs_backoff(k);
 	}
-
-	if (!got_lock)			/* We gotta have our lock */
-		GTMASSERT;
-
-	/* Now run through queue. Verify the fwd and backward chain ptrs */
-	last_qe = (que_ent_ptr_t)qhdr;
-	for (qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
-	     qe != (que_ent_ptr_t)qhdr;
-	     qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl))
-	{
-
-		if ((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) != last_qe)	/* Back pointer works good? */
-		{
-/*                      ASWP(&qhdr->latch, LOCK_AVAILABLE, latch); */
-			GTMASSERT;
-		}
-		last_qe = qe;
-	}
-
+	assertpro(got_lock);			/* We gotta have our lock */
+	i = verify_queue(qhdr);
 	/* Release locks */
 	RELEASE_SWAPLOCK(&qhdr->latch);
 	--fast_lock_count;
-
-	return;
+	return i;
 }
 
-
-void verify_queue(que_head_ptr_t qhdr)
+gtm_uint64_t verify_queue(que_head_ptr_t qhdr)
 {
+	gtm_uint64_t	i;
 	que_ent_ptr_t	qe, last_qe;
 
-	/* Now run through queue. Verify the fwd and backward chain ptrs */
+	/* run through queue. Verify the fwd and backward chain ptrs */
 	last_qe = (que_ent_ptr_t)qhdr;
-	for (qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
+	for (i = 0, qe = (que_ent_ptr_t)((sm_uc_ptr_t)qhdr + qhdr->fl);
 	     qe != (que_ent_ptr_t)qhdr;
-	     qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl))
+	     qe = (que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->fl), i++)
 	{
-
-		if ((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) != last_qe)	/* Back pointer works good? */
-			GTMASSERT;
+		assertpro((que_ent_ptr_t)((sm_uc_ptr_t)qe + qe->bl) == last_qe);	/* Back pointer works good? */
 		last_qe = qe;
 	}
-
-	return;
+	return i;
 }
diff --git a/sr_port/view_arg_convert.c b/sr_port/view_arg_convert.c
index 52d1542..765e28a 100644
--- a/sr_port/view_arg_convert.c
+++ b/sr_port/view_arg_convert.c
@@ -48,19 +48,18 @@ error_def(ERR_VIEWLVN);
 void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *parmblk, boolean_t is_dollar_view)
 {
 	static	int4		first_time = TRUE;
-	int			n, reg_index;
-	ht_ent_mname		*tabent;
-	mstr			tmpstr, namestr;
-	gd_region		*r_top, *r_ptr, *gd_reg_start;
-	mname_entry		gvent, lvent;
-	mident_fixed		lcl_buff;
-	unsigned char		global_names[1024], stashed;
-	unsigned char 		*src, *nextsrc, *src_top, *dst, *dst_top, y;
-	unsigned char		*c, *c_top;
+	char			*cptr;
 	gd_binding		*gd_map;
-	gv_namehead		*tmp_gvt;
+	gd_region		*gd_reg_start, *r_ptr, *r_top;
 	gvnh_reg_t		*gvnh_reg;
 	gvnh_spanreg_t		*gvspan;
+	gv_namehead		*tmp_gvt;
+	ht_ent_mname		*tabent;
+	int			n, reg_index;
+	mident_fixed		lcl_buff;
+	mname_entry		gvent, lvent;
+	mstr			namestr, tmpstr;
+	unsigned char 		*c, *c_top, *dst, *dst_top, global_names[1024], *nextsrc, *src, *src_top, stashed, y;
 
 	switch (vtp_parm)
 	{
@@ -83,9 +82,9 @@ void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *pa
 			parmblk->value = parm;
 			break;
 		case (VTP_NULL | VTP_DBREGION):
-			if (NULL == parm)
+			if ((NULL == parm) || ((1 == parm->str.len) && ('*' == *parm->str.addr)))
 			{
-				parmblk->gv_ptr = 0;
+				parmblk->gv_ptr = NULL;
 				break;
 			}
 			/* caution:  fall through */
@@ -100,18 +99,23 @@ void view_arg_convert(viewtab_entry *vtp, int vtp_parm, mval *parm, viewparm *pa
 				parmblk->gv_ptr = r_ptr;
 			else
 			{
+				for (cptr = parm->str.addr, n = 0; n < parm->str.len; cptr++, n++)
+					lcl_buff.c[n] = TOUPPER(*cptr);		/* Region names are upper-case ASCII */
+				cptr = parm->str.addr;				/* remember the original name */
+				parm->str.addr = (char *)&lcl_buff.c;		/* use the upper case name formed above */
 				for (r_top = r_ptr + gd_header->n_regions; ; r_ptr++)
 				{
 					if (r_ptr >= r_top)
 						rts_error_csa(CSA_ARG(NULL)
 							VARLSTCNT(4) ERR_NOREGION,2, parm->str.len, parm->str.addr);
 					tmpstr.len = r_ptr->rname_len;
-					tmpstr.addr = (char *) r_ptr->rname;
+					tmpstr.addr = (char *)r_ptr->rname;
 					MSTR_CMP(tmpstr, parm->str, n);
 					if (0 == n)
 						break;
 				}
 				parmblk->gv_ptr = r_ptr;
+				parm->str.addr = cptr;				/* be nice and restore the original name */
 			}
 			break;
 		case VTP_DBKEY:
diff --git a/sr_port/viewtab.h b/sr_port/viewtab.h
index f80f090..badcbed 100644
--- a/sr_port/viewtab.h
+++ b/sr_port/viewtab.h
@@ -38,6 +38,7 @@ VIEWTAB("GVFILE",		VTP_DBREGION,			VTK_GVFILE,		MV_STR),
 VIEWTAB("GVFIRST",		VTP_NULL,			VTK_GVFIRST,		MV_STR), /* nodoc : archaic and deprecated.
 												  * use GVNEXT instead */
 VIEWTAB("GVNEXT",		VTP_DBREGION,			VTK_GVNEXT,		MV_STR),
+VIEWTAB("GVSRESET",		VTP_DBREGION | VTP_NULL,	VTK_GVSRESET,		MV_STR),
 VIEWTAB("GVSTATS",		VTP_DBREGION,			VTK_GVSTATS,		MV_STR),
 VIEWTAB("ICHITS",		VTP_NULL,			VTK_ICHITS,		MV_NM),
 VIEWTAB("ICMISS",		VTP_NULL,			VTK_ICMISS,		MV_NM),
@@ -82,15 +83,11 @@ VIEWTAB("NOLVNULLSUBS",		VTP_NULL,			VTK_NOLVNULLSUBS,	MV_NM),
 VIEWTAB("NOUNDEF",		VTP_NULL,			VTK_NOUNDEF,		MV_NM),
 VIEWTAB("PATCODE",		VTP_VALUE | VTP_NULL,		VTK_PATCODE,		MV_STR),
 VIEWTAB("PATLOAD",		VTP_VALUE,			VTK_PATLOAD,		MV_NM),
-#ifdef DEBUG
-VIEWTAB("PROBECRIT",		VTP_DBREGION,			VTK_PROBECRIT,		MV_NM),
-#endif
+VIEWTAB("POOLLIMIT",		VTP_DBREGION | VTP_NULL,	VTK_POOLLIMIT,		MV_NM),
+VIEWTAB("PROBECRIT",		VTP_DBREGION,			VTK_PROBECRIT,		MV_STR),
 VIEWTAB("RCHITS",		VTP_NULL,			VTK_RCHITS,		MV_NM),
 VIEWTAB("RCMISSES",		VTP_NULL,			VTK_RCMISSES,		MV_NM),
 VIEWTAB("RCSIZE",		VTP_NULL,			VTK_RCSIZE,		MV_NM),
-#if defined(DEBUG) && defined(USHBIN_SUPPORTED)
-VIEWTAB("RCTLDUMP",		VTP_NULL,			VTK_RCTLDUMP,		MV_STR),
-#endif
 VIEWTAB("REGION",		VTP_DBKEY,			VTK_REGION,		MV_STR),
 VIEWTAB("RESETGVSTATS",		VTP_NULL,			VTK_RESETGVSTATS,	MV_STR),
 VIEWTAB("RTNCHECKSUM",		VTP_RTNAME,			VTK_RTNCHECKSUM,	MV_STR),
diff --git a/sr_port/wbox_test_init.h b/sr_port/wbox_test_init.h
index 5d3a11c..0409c6b 100644
--- a/sr_port/wbox_test_init.h
+++ b/sr_port/wbox_test_init.h
@@ -140,9 +140,24 @@ typedef enum {
 	WBTEST_INFO_HUB_SEND_ZMESS,		/* 101 : Print messages triggered via ZMESSAGE to the syslog */
 	WBTEST_SKIP_CORE_FOR_MEMORY_ERROR,	/* 102 : Do not generate core file in case of GTM-E-MEMORY fatal error */
 	WBTEST_EXTFILTER_INDUCE_ERROR,		/* 103 : Do not assert in case of external filter error (test induces that) */
+	WBTEST_BADEXEC_UPDATE_PROCESS,		/* 104 : Prevent the update process from EXECing */
+	WBTEST_BADEXEC_HELPER_PROCESS,		/* 105 : Prevent the helper processes from EXECing */
+	WBTEST_BADEDITOR_GETEDITOR,		/* 106 : Have geteditor return that it was unable to find an editor*/
+	WBTEST_BADEXEC_OP_ZEDIT,		/* 107 : Give a invalid executable path to an editor so EXEC will fail*/
+	WBTEST_BADEXEC_SECSHR_PROCESS,		/* 108 : Prevent the SECSHR process from being EXEC'ed */
+	WBTEST_BADDUP_PIPE_STDIN,		/* 109 : Prevent dup2() of stdin in forked piped process */
+	WBTEST_BADDUP_PIPE_STDOUT,		/* 110 : Prevent dup2() of stdout in forked piped process */
+	WBTEST_BADDUP_PIPE_STDERR1,		/* 111 : Prevent dup2() of stderr in forked piped process */
+	WBTEST_BADDUP_PIPE_STDERR2,		/* 112 : Prevent second dup2() of stderr in forked piped process */
+	WBTEST_BADEXEC_PIPE_PROCESS,		/* 113 : Prevent the SECSHR process from being EXEC'ed */
+	WBTEST_MAXGTMDIST_UPDATE_PROCESS,	/* 114 : Make gtm_dist too big for update process */
+	WBTEST_MAXGTMDIST_HELPER_PROCESS,	/* 115 : Make gtm_dist too big for helper process */
+	WBTEST_MAX_TRIGNAME_SEQ_NUM,		/* 116 : Induce "too many triggers" error sooner (MAX_TRIGNAME_SEQ_NUM) */
+	WBTEST_RELINKCTL_MAX_ENTRIES,		/* 117 : Bring down the maximum number of relink control entries in one file */
+	WBTEST_FAKE_BIG_KEY_COUNT		/* 118 : fake large increase in mupip load key count to show it doesn't overflow */
 	/* Note 1: when adding new white box test cases, please make use of WBTEST_ENABLED and WBTEST_ASSIGN_ONLY (defined below)
 	 * whenever applicable
-	 * Note 2: when adding a new white box test case, see if an existing WBTEST_UNUSED* slot can be levereged.
+	 * Note 2: when adding a new white box test case, see if an existing WBTEST_UNUSED* slot can be leveraged.
 	 */
 } wbtest_code_t;
 
diff --git a/sr_port/xfer.h b/sr_port/xfer.h
index bf8e25e..f392284 100644
--- a/sr_port/xfer.h
+++ b/sr_port/xfer.h
@@ -313,7 +313,7 @@ XFER(xf_fnzsocket, op_fnzsocket)
 XFER(xf_fnzsyslog, op_fnzsyslog),
 XFER(xf_zrupdate, op_zrupdate)
 #endif
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 ,
 XFER(xf_rhd_ext, op_rhd_ext),
 XFER(xf_lab_ext, op_lab_ext)
diff --git a/sr_port/zbreak.h b/sr_port/zbreak.h
index c68d0cd..d7e00a2 100644
--- a/sr_port/zbreak.h
+++ b/sr_port/zbreak.h
@@ -15,6 +15,7 @@
 #include <zbreaksp.h>
 #include "cache.h"
 
+/* Structure for each ZBREAK set in the process */
 typedef struct
 {
 	zb_code		*mpc;		/* MUMPS address for ZBREAK */
@@ -23,9 +24,12 @@ typedef struct
 	int		offset;
 	int		count;		/* # of time ZBREAK encountered */
 	cache_entry	*action;	/* action associated with ZBREAK (indirect cache entry) */
+	rhdtyp		*rtnhdr;	/* Routine header of routine containing ZBREAK */
 	zb_code 	m_opcode;	/* MUMPS op_code replaced */
+	char		filler[SIZEOF(char *) - SIZEOF(zb_code)];
 } zbrk_struct;
 
+/* ZBREAK anchoring structure */
 typedef struct
 {
 	zbrk_struct	*beg;
@@ -46,9 +50,9 @@ typedef struct
 #define SIZEOF_LA	0
 
 zbrk_struct *zr_find(z_records *zrecs, zb_code *addr);
-zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr);
+zbrk_struct *zr_add_zbreak(z_records *zrecs, zb_code *addr);
 void zr_init(z_records *zrecs, int4 count);
-void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr);
+void zr_remove_zbreak(z_records *zrecs, zbrk_struct *z_ptr);
 zb_code *find_line_call(void *addr);
 void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger);
 
diff --git a/sr_port/zlput_rname.c b/sr_port/zlput_rname.c
index e766bb1..cca5129 100644
--- a/sr_port/zlput_rname.c
+++ b/sr_port/zlput_rname.c
@@ -49,6 +49,16 @@ STATICFNDCL boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *
 GBLREF rtn_tabent	*rtn_fst_table, *rtn_names, *rtn_names_end, *rtn_names_top;
 GBLREF stack_frame	*frame_pointer;
 
+/* Routine to perform routine table maintenance. In addition, if a routine is being replaced instead of just added, performs
+ * the necessary maintenance to the replaced routine.
+ *
+ * Parameter:
+ *   hdr - routine header address of the routine header just linked in
+ *
+ * Return value:
+ *   TRUE  - If routine updated/added.
+ *   FALSE - If routine could not be updated/added.
+ */
 bool zlput_rname (rhdtyp *hdr)
 {
 	rhdtyp		*old_rhead, *rhead;
@@ -95,7 +105,7 @@ bool zlput_rname (rhdtyp *hdr)
 		if (!handle_active_old_versions(&duplicated, old_rhead, hdr))
 			return FALSE;
 		if (!duplicated)
-			zr_unlink_rtn(old_rhead, FALSE); /* Release private code sections no longer in use */
+			zr_unlink_rtn(old_rhead, FALSE); /* Free releasable pieces of old routines */
 #		ifndef USHBIN_SUPPORTED
 		hdr->old_rhead_ptr = (int4)old_rhead;
 #		else /* USHBIN_SUPPORTED */
@@ -115,6 +125,10 @@ bool zlput_rname (rhdtyp *hdr)
  * Parameters:
  *   rtnhdr	    - The routine header to start our backwards search at.
  *   need_duplicate - Address of boolean_t to set if is the exact same routine (same routine header address).
+ *
+ * Return value:
+ *   TRUE -  If a stack frame specifies the supplied routine header.
+ *   FALSE - If no stack frame specifies the supplied routine header.
  */
 boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate)
 {
@@ -135,10 +149,23 @@ boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate)
 	return FALSE;
 }
 
+/* Routine to:
+ *   1. Check if the specified routine is currently on the M stack and if it is then
+ *   2. If we are running with VIEW LINK:RECURSIVE.
+ *   3. If no, then return FALSE to signify need for an error.
+ *   4. If yes, we need to do a number of things to allow both versions of the same routine to
+ *      exist on the M stack at the same time.
+ *
+ * Parameters:
+ *   duplicated  - Pointer to boolean return flag indicating we duplicated the input routine header and
+ *                 related fields.
+ *   old_rhead   - The routine header being replaced/checked.
+ *   hdr         - The new routine header doing the replacing.
+ */
 STATICFNDEF boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *old_rhead, rhdtyp *hdr)
 {
 	stack_frame	*fp;
-	rhdtyp 		*rhead, *new_rhead;
+	rhdtyp 		*rhead, *copy_rhead;
 	boolean_t	need_duplicate, is_on_stack;
 	ssize_t		sect_rw_nonrel_size;
 	DCL_THREADGBL_ACCESS;
@@ -157,26 +184,70 @@ STATICFNDEF boolean_t handle_active_old_versions(boolean_t *duplicated, rhdtyp *
 	}
 #	ifdef USHBIN_SUPPORTED
 	if (need_duplicate)
-	{
-		new_rhead = (rhdtyp *)malloc(SIZEOF(rhdtyp));
-		*new_rhead = *old_rhead;
-		new_rhead->current_rhead_adr = new_rhead;
-		old_rhead->active_rhead_adr = new_rhead; /* Reserve previous version on active chain */
+	{	/* The routine is on the M stack so is active. To allow it to stay there while we also link in a newer version
+		 * we need to make some changes to the older version. The way the replaced routine would normally be handled if
+		 * we weren't keeping it is the various sections of it would be released and the fields in its routine header be
+		 * reset to point to those sections in the latest version. That's still going to happen so what we do here is to
+		 * create a SEPARATE copy of the routine header that WON'T be modified so all its fields are intact and as they
+		 * were along with a separate copy of the label table since the replacement process also resets the label table
+		 * to point to the new version of the routine. Lastly, we'll run back through the stack changing the stack frame's
+		 * "rvector" field to point to the copied routine header so it continues to work as it did.
+		 */
+		copy_rhead = (rhdtyp *)malloc(SIZEOF(rhdtyp));
+		*copy_rhead = *old_rhead;
+		copy_rhead->current_rhead_adr = copy_rhead;	/* Grabs of current fhead need to stay with this one for this
+								 * older version
+								 */
+		copy_rhead->old_rhead_adr = old_rhead;	/* Link copied routine back to its original flavor. Used to know which
+							 * routine should have its active_rhead_adr field cleared when the copy
+							 * becomes inactive and gets cleaned up.
+							 */
+		assert(NULL == old_rhead->active_rhead_adr);
+		old_rhead->active_rhead_adr = copy_rhead; /* Reserve previous version on active chain */
 		for (fp = frame_pointer; NULL != fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
 			if (CURRENT_RHEAD_ADR(fp->rvector) == old_rhead)
-				fp->rvector = new_rhead; /* Point frame's code vector at reserved copy of old routine version */
-		/* Any field (e.g. the label table) that is currently shared by old_rhead needs to be copied to a separate area
-		 * other fields (e.g. literal mvals) will be redirected for old_rhead, so we just need to keep the older version
-		 * around (don't free it).
+				fp->rvector = copy_rhead; /* Point frame's code vector at reserved copy of old routine version */
+		/* Need to preserve original copy of label table for as long as this routine is active since it is used by
+		 * routines like get_symb_line (or symb_line() it calls) and find_line_start() and find_line_addr(). Once the
+		 * routine is no longer active, this label table and the copied routine header can go away since no other
+		 * routine would have been able to resolve to it. We call the label table copy sect_rw_nonrel_* here because
+		 * that is how this section is identified everywhere else. But here, it is releasable when inactive.
 		 */
 		sect_rw_nonrel_size = old_rhead->labtab_len * SIZEOF(lab_tabent);
-		new_rhead->labtab_adr = (lab_tabent *)malloc(sect_rw_nonrel_size);
-		memcpy(new_rhead->labtab_adr, old_rhead->labtab_adr, sect_rw_nonrel_size);
-		/* Make sure to: skip urx_remove, do not free code section, etc. */
-		/* ALSO: We need to go through resolve linkage table entries corresponding to this the old version, and re-resolve
-		 * them to point into the new version */
+		copy_rhead->labtab_adr = (lab_tabent *)malloc(sect_rw_nonrel_size);
+		memcpy(copy_rhead->labtab_adr, old_rhead->labtab_adr, sect_rw_nonrel_size);
+		copy_rhead->rtn_relinked = TRUE; /* This flag is checked on unwind to see if routine should be cleaned up */
 		*duplicated = TRUE;
 	}
 #	endif /* USHBIN_SUPPORTED */
 	return TRUE;
 }
+
+#ifdef USHBIN_SUPPORTED
+/* Routine called from op_unwind/unw_retarg/flush_jmp (via CLEANUP_COPIED_RECURSIVE_RTN macro) when a routine pops with the
+ * rtn_relinked flag set indicating potential need to clean up a copied routine header and label table - along with the rest
+ * of the routine's pieces which were purposely bypassed since the routine was on the M stack at the time.
+ */
+void zr_cleanup_recursive_rtn(rhdtyp *rtnhdr)
+{
+	stack_frame	*fp;
+
+	/* See if routine is still in use */
+	for (fp = frame_pointer; fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
+	{
+		if (rtnhdr == fp->rvector)
+			break; /* Found reference - not done with it */
+	}
+	if (NULL == fp)
+	{	/* We reached the end of the stack without finding the routine, seems ripe for cleaning */
+		assert(rtnhdr->old_rhead_adr->active_rhead_adr == rtnhdr);
+		assert(NULL == rtnhdr->active_rhead_adr);
+		zr_unlink_rtn(rtnhdr, FALSE);			/* Cleans up the copy */
+		assert(!rtnhdr->has_ZBREAK);
+		assert(!rtnhdr->old_rhead_adr->has_ZBREAK);	/* These should both be cleared now if ever set */
+		free(rtnhdr->labtab_adr);
+		rtnhdr->old_rhead_adr->active_rhead_adr = NULL;
+		free(rtnhdr);
+	}
+}
+#endif /* USHBIN_SUPPORTED */
diff --git a/sr_port/zr_get_free.c b/sr_port/zr_add_zbreak.c
similarity index 78%
rename from sr_port/zr_get_free.c
rename to sr_port/zr_add_zbreak.c
index b5b0b6a..4a5d6a8 100644
--- a/sr_port/zr_get_free.c
+++ b/sr_port/zr_add_zbreak.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2009 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -16,22 +16,22 @@
 #include <rtnhdr.h>
 #include "zbreak.h"
 
-zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr)
+zbrk_struct *zr_add_zbreak(z_records *zrecs, zb_code *addr)
 {
 	z_records	temp;
 	zbrk_struct 	*z_ptr;
 
-	/* NOTE: records are stored by decreasing addresses */
+	/* NOTE: Records are stored by decreasing addresses */
 	assert(zrecs->free < zrecs->end);
 	for (z_ptr = zrecs->beg; z_ptr < zrecs->free; z_ptr++)
 	{
 		if (z_ptr->mpc == addr)
 			return (z_ptr);
-		if (z_ptr->mpc < addr)	/* insert here */
+		if (z_ptr->mpc < addr)		/* Insert here */
 			break;
 	}
 	assert(z_ptr == zrecs->free || z_ptr->mpc < addr);
-	if (1 == zrecs->end - zrecs->free)	/* expand if necessary */
+	if (1 == zrecs->end - zrecs->free)	/* Expand if necessary */
 	{
 		temp = *zrecs;
 		zr_init(zrecs, 2 * (int)(zrecs->end - zrecs->beg));
@@ -42,7 +42,7 @@ zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr)
 		z_ptr = zrecs->beg + (z_ptr - temp.beg);
 		free(temp.beg);
 	}
-	/* shift records down into the bottom spot which was allocated */
+	/* Shift records down into the bottom spot which was allocated */
 	memmove((char *)(z_ptr + 1), (char *)z_ptr, (zrecs->free - z_ptr) * SIZEOF(zbrk_struct));
 	memset((char *)z_ptr, 0, SIZEOF(zbrk_struct));
 	z_ptr->mpc = addr;
diff --git a/sr_port/zr_put_free.c b/sr_port/zr_remove_zbreak.c
similarity index 55%
rename from sr_port/zr_put_free.c
rename to sr_port/zr_remove_zbreak.c
index 75524f0..e2018a9 100644
--- a/sr_port/zr_put_free.c
+++ b/sr_port/zr_remove_zbreak.c
@@ -20,10 +20,10 @@
 #include "private_code_copy.h"
 #include "gtm_text_alloc.h"
 
-void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
+void zr_remove_zbreak(z_records *zrecs, zbrk_struct *z_ptr)
 {
 	mstr		rtn_str;
-	rhdtyp		*routine;
+	rhdtyp		*routine, *rtncopy;
 	boolean_t	deleted;
 
 	assert(zrecs->beg  <= zrecs->free);
@@ -32,22 +32,22 @@ void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
 	assert(z_ptr <= zrecs->free);
 	if (NULL != z_ptr->action)
 	{	/* An action exists, reduce our interest in it */
-		assert(z_ptr->action->zb_refcnt > 0);
+		assert(0 < z_ptr->action->zb_refcnt);
 		z_ptr->action->zb_refcnt--;
 		if (0 == z_ptr->action->zb_refcnt)
 			z_ptr->action = NULL;
 	}
-	/* In the generated code, change the offset in TRANSFER TABLE */
+	/* In the generated code, change the opcode in the instruction */
 #	ifdef COMPLEX_INSTRUCTION_UPDATE
 	EXTRACT_AND_UPDATE_INST(z_ptr->mpc, z_ptr->m_opcode);
 #	else
 	*z_ptr->mpc = z_ptr->m_opcode;
-#	endif
+#	endif /* COMPLEX_INSTRUCTION_UPDATE */
 	inst_flush(z_ptr->mpc, SIZEOF(INST_TYPE));
 #	ifdef USHBIN_SUPPORTED
-	if (((z_ptr == zrecs->beg) || !MIDENT_EQ((z_ptr - 1)->rtn, z_ptr->rtn)) &&
-	    (((z_ptr + 1) == zrecs->free) || !MIDENT_EQ((z_ptr + 1)->rtn, z_ptr->rtn)))
-	{	/* No more breakpoints in the routine we just removed a break from. Note that since zrecs is sorted based
+	if (((z_ptr == zrecs->beg) || ((z_ptr - 1)->rtnhdr != z_ptr->rtnhdr))
+	    && (((z_ptr + 1) == zrecs->free) || ((z_ptr + 1)->rtnhdr != z_ptr->rtnhdr)))
+	{	/* No more breakpoints in the routine we just removed a ZBREAK from. Note that since zrecs is sorted based
 		 * on mpc, all breakpoints in a given routine are bunched together. Hence, it is possible to determine
 		 * if all breakpoints are deleted from a routine by checking the preceding and succeeding entries of the
 		 * one we are removing.
@@ -55,16 +55,30 @@ void zr_put_free(z_records *zrecs, zbrk_struct *z_ptr)
 		assert(0 != z_ptr->rtn->len);
 		rtn_str.len = z_ptr->rtn->len;
 		rtn_str.addr = z_ptr->rtn->addr;
-		routine = find_rtn_hdr(&rtn_str);
-		if (NULL != routine->shared_ptext_adr) /* don't need the private copy any more, revert back to shared copy */
-			release_private_code_copy(routine);
+		routine = rtncopy = z_ptr->rtnhdr;
+		assert(NULL != routine);
+		/* We now have the routine header associated with this ZBREAK. But if this routine was recursively relinked
+		 * AND shared, then the address we need to check about releasing is associated with the copy of the routine
+		 * header/code we made for the recursive link (see handle_active_old_versions() for description).
+		 */
+		if (NULL != routine->active_rhead_adr)
+		{
+			rtncopy = routine->active_rhead_adr;
+			rtncopy->has_ZBREAK = FALSE;
+		}
+		if (NULL != rtncopy->shared_ptext_adr) 		/* Revert back to shared copy of routine */
+		{
+			assert(rtncopy->shared_ptext_adr != rtncopy->ptext_adr);
+			release_private_code_copy(rtncopy);
+		}
+		routine->has_ZBREAK = FALSE;	/* Indicate no more ZBREAKs in this routine */
 	}
-#	endif
+#	endif /* USHBIN_SUPPORTED */
 	zrecs->free--;
-	/* potentially overlapped memory, use memmove, not memcpy */
+	/* Potentially overlapped memory, use memmove, not memcpy */
 	memmove((char *)z_ptr, (char *)(z_ptr + 1), (zrecs->free - z_ptr) * SIZEOF(zbrk_struct));
 	if (zrecs->free == zrecs->beg)
-	{	/* all breaks gone, free space allocated for breakpoints */
+	{	/* All ZBREAKS gone, free space allocated for breakpoints */
 		free(zrecs->beg);
 		zrecs->beg = NULL;
 		zrecs->free = NULL;
diff --git a/sr_port/zr_remove_zbrks.c b/sr_port/zr_remove_zbrks.c
index f8a2dee..39a005c 100644
--- a/sr_port/zr_remove_zbrks.c
+++ b/sr_port/zr_remove_zbrks.c
@@ -24,13 +24,24 @@ GTMTRIG_ONLY(error_def(ERR_TRIGZBREAKREM);)
 /* Remove all ZBREAKs in given rtn */
 void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger)
 {
+	rhdtyp			*rtn_look;
 	zbrk_struct		*zb_ptr;
 	GTMTRIG_ONLY(boolean_t	msg_done = FALSE;)
 
+	rtn_look = rtn;		/* Initially routine to look for is same */
+#	ifdef USHBIN_SUPPORTED
+	if ((NULL != rtn) && (rtn->rtn_relinked))
+	{	/* For a recursively linked routine, the saved routine header is actually the original, not the
+		 * copy we were supplied by caller.
+		 */
+		rtn_look = rtn->old_rhead_adr;
+	}
+#	endif /* USHBIN_SUPPORTED */
 	for (zb_ptr = zbrk_recs.free - 1; NULL != zbrk_recs.beg && zb_ptr >= zbrk_recs.beg; zb_ptr--)
 	{	/* Go in the reverse order to reduce memory movement in zr_put_free() */
-		if ((NULL == rtn) || (ADDR_IN_CODE(((unsigned char *)zb_ptr->mpc), rtn)))
+		if ((NULL == rtn_look) || (zb_ptr->rtnhdr == rtn_look))
 		{
+			assert((NULL == rtn_look) || (ADDR_IN_CODE(((unsigned char *)zb_ptr->mpc), rtn)));
 #			ifdef GTM_TRIGGER
 			if ((BREAKMSG == notify_is_trigger) && !msg_done && (break_message_mask & TRIGGER_ZBREAK_REMOVED_MASK))
 			{	/* Message is info level */
@@ -39,7 +50,7 @@ void zr_remove_zbrks(rhdtyp *rtn, boolean_t notify_is_trigger)
 				msg_done = TRUE;
 			}
 #			endif
-			zr_put_free(&zbrk_recs, zb_ptr);
+			zr_remove_zbreak(&zbrk_recs, zb_ptr);
 		}
 	}
 	return;
diff --git a/sr_port/zr_unlink_rtn.c b/sr_port/zr_unlink_rtn.c
index 3005298..bc7885e 100644
--- a/sr_port/zr_unlink_rtn.c
+++ b/sr_port/zr_unlink_rtn.c
@@ -14,7 +14,6 @@
 #include <stddef.h>	/* for offsetof macro */
 #include "gtm_stdlib.h"
 #include "gtm_string.h"
-#include "sys/mman.h"
 
 #include <rtnhdr.h>
 #include "fix_pages.h"
@@ -27,6 +26,9 @@
 #include "zr_unlink_rtn.h"
 #include "zroutines.h"
 #include "incr_link.h"
+#ifdef UNIX
+#include "rtnobj.h"
+#endif
 
 /* Routine to unlink given old flavor of routine (as much of it as we are able).
  *
@@ -42,7 +44,6 @@
  */
 void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
 {
-	unsigned char	*map_adr;	/* If code section is mmapped from shared .o file */
 	textElem        *telem;
 	rhdtyp		*rhdr, *next_rhdr;
 
@@ -69,14 +70,11 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
         {	/* Object is not resident in a shared library */
 		if (!free_all)
 			zlmov_lnames(old_rhead); 	/* Copy the label names from literal pool to malloc'd area */
-		if (0 < old_rhead->shared_len)
-		{	/* Object is being shared via mmap() */
-			assert(NULL != old_rhead->shared_ptext_adr);
-			assert(old_rhead->shared_ptext_adr == old_rhead->ptext_adr);
-			map_adr = old_rhead->shared_ptext_adr  - SIZEOF(rhdtyp)- NATIVE_HDR_LEN;
-			munmap(map_adr, old_rhead->shared_len);
-
-		} else
+#		ifdef AUTORELINK_SUPPORTED
+		if (old_rhead->shared_object)
+			rtnobj_shm_free(old_rhead, LATCH_GRABBED_FALSE); /* Object is shared via rtnobj shared memory */
+		else
+#		endif
 		{	/* Process private linked object */
 			GTM_TEXT_FREE(old_rhead->ptext_adr);
 		}
@@ -92,20 +90,27 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
 	old_rhead->vartab_adr = NULL;
 	free(old_rhead->linkage_adr);		/* Release the old linkage section */
 	old_rhead->linkage_adr = NULL;
-#	else
+#	ifdef AUTORELINK_SUPPORTED
+	if (NULL != old_rhead->zhist)
+	{	/* Free history used for autorelink if present */
+		free(old_rhead->zhist);
+		old_rhead->zhist = NULL;
+	}
+#	endif /* AUTORELINK_SUPPORTED */
+#	else  /* (now) !USHBIN_SUPPORTED */
 	if (!old_rhead->old_rhead_ptr)
-	{	/* On VMS, this makes the routine "malleable" and on UNIX tiz a stub */
+	{	/* On VMS, this makes the routine "malleable" and on UNIX tiz currently a stub */
 	        fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead)
 			  + (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len));
 	}
-#	endif
+#	endif /* !USHBIN_SUPPORTED */
 	if (free_all)
 	{	/* We are not keeping any parts of this routine (generally used for triggers and for gtm_unlink_all()) */
 #		ifdef USHBIN_SUPPORTED
 		free(old_rhead->labtab_adr);	/* Usually non-releasable but not in this case */
 		if (old_rhead->lbltext_ptr)
 			free(old_rhead->lbltext_ptr);	/* Get rid of any label text hangers-on */
-		if (old_rhead->shared_len)		/* If this is a shared object (not library), drop rtn name/path text */
+		if (old_rhead->shared_object)		/* If this is a shared object (not library), drop rtn name/path text */
 			free(old_rhead->src_full_name.addr);
 		/* Run the chain of old (replaced) versions freeing them also if they exist*/
 		for (rhdr = OLD_RHEAD_ADR(old_rhead); NULL != rhdr; rhdr = next_rhdr)
@@ -113,7 +118,7 @@ void zr_unlink_rtn(rhdtyp *old_rhead, boolean_t free_all)
 			next_rhdr = rhdr->old_rhead_adr;
 			if (rhdr->lbltext_ptr)
 				free(rhdr->lbltext_ptr);	/* Get rid of any label text hangers-on */
-			if (rhdr->shared_len)			/* If this is a shared object, drop rtn name/path text */
+			if (rhdr->shared_object)		/* If this is a shared object, drop rtn name/path text */
 				free(rhdr->src_full_name.addr);
 			free(rhdr->labtab_adr);			/* Free dangling label table */
 			free(rhdr);
diff --git a/sr_port/zshow.h b/sr_port/zshow.h
index ca5893f..19dc01f 100644
--- a/sr_port/zshow.h
+++ b/sr_port/zshow.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -98,9 +98,14 @@ void		zshow_zwrite(zshow_out *output);
 boolean_t	zwr2format(mstr *src, mstr *des);
 int		zwrkeyvallen(char* ptr, int len, char **val_off, int *val_len, int *val_off1, int *val_len1);
 int		format2zwr(sm_uc_ptr_t src, int src_len, unsigned char *des, int *des_len);
+void		format2disp(char *src, int src_len, char *dispbuff, int *displen);
 void		mval_write(zshow_out *output, mval *v, boolean_t flush);
 void		mval_nongraphic(zshow_out *output, char *cp, int len, int num);
 void		gvzwr_fini(zshow_out *out, int pat);
 void		lvzwr_fini(zshow_out *out, int t);
 
+#ifdef AUTORELINK_SUPPORTED
+void		zshow_rctldump(zshow_out *output);
+#endif
+
 #endif
diff --git a/sr_port/zshow_output.c b/sr_port/zshow_output.c
index 210e05f..2f29f3b 100644
--- a/sr_port/zshow_output.c
+++ b/sr_port/zshow_output.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -41,7 +41,19 @@
 #define F_SUBSC_LEN		 3
 #define N_SUBSC_LEN		 5
 #define MIN_DATASIZE		40
-#define	ZSHOW_SPACE_INDENT	10	/* # of spaces every following line of zshow output is indented with */
+
+#define WRITE_ONE_LINE_FROM_BUFFER			\
+{							\
+	mv->str.addr = out->buff;			\
+	mv->str.len = INTCAST(out->ptr - out->buff);	\
+	mv->mvtype = MV_STR;				\
+	op_write(mv);					\
+	op_wteol(1);					\
+	out->ptr = out->buff;				\
+	out->len = 0;					\
+	out->displen = 0;				\
+	out->line_num++;				\
+}
 
 GBLREF	io_pair		io_curr_device;
 GBLREF	spdesc		stringpool;
@@ -61,7 +73,7 @@ void zshow_output(zshow_out *out, const mstr *str)
 	mval		*mv, lmv;
 	lv_val		*lv, *lv_child;
 	char		buff, *strptr, *strnext, *strtop, *strbase, *leadptr;
-	int		key_ovrhd, str_processed, n_spaces, sbs_depth, dbg_sbs_depth;
+	int		key_ovrhd, str_processed, sbs_depth, dbg_sbs_depth;
 	ssize_t        	len, outlen, chcnt, char_len, disp_len ;
 	int		buff_len;
 	int		device_width, inchar_width, cumul_width;
@@ -101,10 +113,7 @@ void zshow_output(zshow_out *out, const mstr *str)
 			str_processed = 0;
 		}
 		device_width = io_curr_device.out->width;
-		/* Do not indent if width is < the indentation length or if remaining width cannot accommodate one character */
-		n_spaces = (device_width > (ZSHOW_SPACE_INDENT UNICODE_ONLY(+ (gtm_utf8_mode ? GTM_MB_DISP_LEN_MAX : 0)))
-			? ZSHOW_SPACE_INDENT : 0);
-		if (str && (disp_len + out->displen > device_width))
+		if (str)
 		{
 			for (; (len > 0) && (disp_len + out->displen > device_width); )
 			{
@@ -143,37 +152,15 @@ void zshow_output(zshow_out *out, const mstr *str)
 				char_len -= chcnt;
 				assert((UNICODE_ONLY((gtm_utf8_mode) ?
 						     (ssize_t)UTF8_LEN_STRICT(strptr, (int)len) :) len) == char_len);
-				mv->str.addr = out->buff;
-				mv->str.len = INTCAST(out->ptr - out->buff);
-				mv->mvtype = MV_STR;
-				op_write(mv);
-				op_wteol(1);
-				out->ptr = out->buff + n_spaces;
-				memset(out->buff, ' ', n_spaces);
-				out->len = n_spaces;
-				out->displen = n_spaces;
-				out->line_num++;
+				WRITE_ONE_LINE_FROM_BUFFER;
 			}
-		}
-		if (str)
-		{
 			memcpy(out->ptr, str->addr + str_processed, len);
 			out->ptr += len;
 			out->len += (int)char_len;
 			out->displen += (int)disp_len;
 		}
 		if (out->flush && out->ptr != out->buff)
-		{
-			mv->str.addr = out->buff;
-			mv->str.len = INTCAST(out->ptr - out->buff);
-			mv->mvtype = MV_STR;
-			op_write(mv);
-			op_wteol(1);
-			out->ptr = out->buff;
-			out->len = 0;
-			out->displen = 0;
-			out->line_num++;
-		}
+			WRITE_ONE_LINE_FROM_BUFFER
 		break;
 	case ZSHOW_LOCAL:
 		if (out->code)
@@ -254,8 +241,7 @@ void zshow_output(zshow_out *out, const mstr *str)
 						memcpy(mv->str.addr, &out->buff[0], mv->str.len);
 						stringpool.free += mv->str.len;
 						lv->v = *mv;
-						out->ptr = out->buff + 10;
-						memset(out->buff, ' ', 10);
+						out->ptr = out->buff;
 						out->line_num++;
 					}
 				}
@@ -360,8 +346,7 @@ void zshow_output(zshow_out *out, const mstr *str)
 				memcpy(mv->str.addr, &out->buff[0], mv->str.len);
 				stringpool.free += mv->str.len;
 				op_gvput(mv);
-				out->ptr = out->buff + 10;
-				memset(out->buff, ' ', 10);
+				out->ptr = out->buff;
 				out->line_num++;
 			}
 		}
diff --git a/sr_port/zshow_svn.c b/sr_port/zshow_svn.c
index a79c62c..01ee873 100644
--- a/sr_port/zshow_svn.c
+++ b/sr_port/zshow_svn.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -109,6 +109,7 @@ static readonly char zsystem_text[] = "$ZSYSTEM";
 #ifdef GTM_TRIGGER
 static readonly char ztname_text[] = "$ZTNAME";
 static readonly char ztdata_text[] = "$ZTDATA";
+static readonly char ztdelim_text[] = "$ZTDELIM";
 #endif
 static readonly char ztexit_text[] = "$ZTEXIT";
 GTMTRIG_ONLY(static readonly char ztlevel_text[] = "$ZTLEVEL";)
@@ -161,6 +162,7 @@ GBLREF boolean_t	dollar_zquit_anyway;
 #ifdef GTM_TRIGGER
 GBLREF mstr		*dollar_ztname;
 GBLREF mval		*dollar_ztdata;
+GBLREF mval		*dollar_ztdelim;
 GBLREF mval		*dollar_ztoldval;
 GBLREF mval		*dollar_ztriggerop;
 GBLREF mval		dollar_ztslate;
@@ -674,6 +676,18 @@ void zshow_svn(zshow_out *output, int one_sv)
 			mval_write(output, &var, TRUE);
 			if (SV_ALL != one_sv)
 				break;
+		/* CAUTION: fall through */
+		case SV_ZTDELIM:
+			if (NULL != dollar_ztdelim && (0 < dollar_ztdelim->str.len))
+			{
+				var.mvtype = MV_STR;
+				var.str = dollar_ztdelim->str;
+			} else
+				memcpy(&var, &literal_null, SIZEOF(mval));
+			ZS_VAR_EQU(&x, ztdelim_text);
+			mval_write(output, &var, TRUE);
+			if (SV_ALL != one_sv)
+				break;
 #		endif
 		/* CAUTION: fall through */
 		case SV_ZTEXIT:
diff --git a/sr_unix/CMakeLists.txt b/sr_unix/CMakeLists.txt
index 40f5eb4..d07f854 100644
--- a/sr_unix/CMakeLists.txt
+++ b/sr_unix/CMakeLists.txt
@@ -60,8 +60,6 @@ set(gtm_osarch_libs "")
 set(gt_src_list)
 set(sources_used "")
 set(extralibs "")
-set(GTMCRYPTLIB "GCRYPT")
-set(GTMCRYPTALGO "AES256CFB")
 message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
 # Establish platform
 # Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true
@@ -76,7 +74,6 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
 else()
   message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
 endif()
-message("--> Encryption Library = ${GTMCRYPTLIB} / Algorithm = ${GTMCRYPTALGO}")
 
 # Choose where to get bootstrap sources.
 set(GTM_DIST "" CACHE PATH "Existing GT.M Distribution")
@@ -461,14 +458,50 @@ foreach(tlslib ssl crypto config)
   set(TLS_LIBRARIES ${TLS_LIBRARIES} ${TLSLIB_${tlslib}})
 endforeach()
 
-add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES})
-set_target_properties(libgtmcrypt PROPERTIES
-  OUTPUT_NAME gtmcrypt
-  COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_${GTMCRYPTALGO}"
+# Building the three encryption libraries could by a loop of some sort, but
+# manually creating each target is way easier.
+
+# Library=GCRYPT Algorithm=AES256CFB
+add_library(libgtmcrypt_gcrypt_AES256CFB.so MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_gcrypt_AES256CFB.so PROPERTIES
+  OUTPUT_NAME gtmcrypt_gcrypt_AES256CFB
+  COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB"
+  LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+  )
+target_link_libraries(libgtmcrypt_gcrypt_AES256CFB.so ${GPG_LIBRARIES})
+install(TARGETS libgtmcrypt_gcrypt_AES256CFB.so DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Establish the default encryption link
+set(default_encr_link   ${GTM_BINARY_DIR}/plugin/libgtmcrypt.so)
+set(default_encr_target libgtmcrypt_gcrypt_AES256CFB.so)
+add_custom_command(
+	OUTPUT ${default_encr_link}
+	COMMAND ${CMAKE_COMMAND} -E create_symlink "${default_encr_target}" "${default_encr_link}"
+	DEPENDS ${GTM_BINARY_DIR}/plugin/${default_encr_target}
+	COMMENT "Generating default_encr symbolic link"
+	)
+add_custom_target(install_default_encr ALL DEPENDS ${default_encr_link})
+install(FILES ${default_encr_link} DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=AES256CFB
+add_library(libgtmcrypt_openssl_AES256CFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_AES256CFB PROPERTIES
+  OUTPUT_NAME gtmcrypt_openssl_AES256CFB
+  COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_AES256CFB"
+  LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
+  )
+target_link_libraries(libgtmcrypt_openssl_AES256CFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_AES256CFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
+
+# Library=OPENSSL Algorithm=BLOWFISHCFB
+add_library(libgtmcrypt_openssl_BLOWFISHCFB MODULE ${libgtmcrypt_SOURCES})
+set_target_properties(libgtmcrypt_openssl_BLOWFISHCFB PROPERTIES
+  OUTPUT_NAME gtmcrypt_openssl_BLOWFISHCFB
+  COMPILE_DEFINITIONS "USE_OPENSSL -DUSE_BLOWFISHCFB"
   LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin
   )
-target_link_libraries(libgtmcrypt ${GPG_LIBRARIES})
-install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin)
+target_link_libraries(libgtmcrypt_openssl_BLOWFISHCFB ${GPG_LIBRARIES} ${TLS_LIBRARIES})
+install(TARGETS libgtmcrypt_openssl_BLOWFISHCFB DESTINATION ${GTM_INSTALL_DIR}/plugin)
 
 add_library(libgtmtls MODULE ${libgtmtls_SOURCES})
 set_target_properties(libgtmtls PROPERTIES
@@ -482,7 +515,7 @@ install(TARGETS libgtmtls DESTINATION ${GTM_INSTALL_DIR}/plugin)
 add_executable(maskpass ${maskpass_SOURCES})
 target_link_libraries(maskpass ${GPG_LIBRARIES} ${TLS_LIBRARIES})
 set_target_properties(maskpass PROPERTIES
-  COMPILE_DEFINITIONS "USE_${GTMCRYPTLIB} -DUSE_SYSLIB_FUNCS"
+  COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_SYSLIB_FUNCS"
   RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt
   )
 install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt)
diff --git a/sr_unix/Makefile.mk b/sr_unix/Makefile.mk
index 7e3789c..c004326 100644
--- a/sr_unix/Makefile.mk
+++ b/sr_unix/Makefile.mk
@@ -26,8 +26,12 @@ endif
 
 DISTDIR = $(gtm_dist)
 PLUGINDIR = $(DISTDIR)/plugin
+GTMCRYPTDIR = $(PLUGINDIR)/gtmcrypt
 CURDIR = `pwd`
 
+# Find out whether we are already in $gtm_dist/plugin/gtmcrypt directory.
+NOT_IN_GTMCRYPTDIR = $(shell [ "$(CURDIR)" = "$(GTMCRYPTDIR)" ] ; echo $$?)
+
 # Determine machine and OS type.
 UNAMESTR = $(shell uname -a)
 MACHTYPE = $(shell uname -m)
@@ -35,7 +39,7 @@ MACHTYPE = $(shell uname -m)
 ifneq (,$(findstring Linux,$(UNAMESTR)))
 	FILEFLAG = -L
 endif
-# 64 bit system? 0 for yes!
+# 64 bit version of GT.M? 0 for yes!
 BIT64 = $(shell file $(FILEFLAG) $(DISTDIR)/mumps | grep -q -E '64-bit|ELF-64'; echo $$?)
 
 # Default installation target. This allows for the build system to randomize `thirdparty' and `algo' thereby changing the default
@@ -52,10 +56,9 @@ else
 endif
 
 CC = cc
-LD = $(CC)
 
 # Setup common compiler flags
-CFLAGS = -c $(debug_flag) $(optimize) -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE64_SOURCE=1
+CFLAGS = $(debug_flag) $(optimize) -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE64_SOURCE=1
 
 ifneq ($(gcrypt_nofips),0)
 	gcrypt_nofips_flag = -DGCRYPT_NO_FIPS
@@ -119,7 +122,10 @@ ifneq (,$(findstring AIX,$(UNAMESTR)))
 	CFLAGS += -qro -qroconst -q64
 	# -q64 for 64-bit object generation
 	# -brtl for allowing both '.a' and '.so' to be searched at runtime.
-	LDFLAGS = -q64 -brtl
+	# -bhalt:5 is to disable warnings about duplicate symbols that come from
+	#  libgtmcryptutil.so and other .so that need pulling the same object
+	#  file (/lib/crt0_64.o)
+	LDFLAGS = -q64 -brtl -bhalt:5
 	RPATHFLAGS =
 	# -G so that we can build shared library
 	# -bexpall exports all symbols from the shared library.
@@ -145,81 +151,67 @@ LDFLAGS += $(LIBFLAGS) -o
 
 COMMON_LIBS = -lgtmcryptutil -lconfig
 
-# List of all files needed for building the encryption plugin.
+# Lists of all files needed for building the encryption plugin.
+crypt_util_srcfiles = gtmcrypt_util.c
+crypt_util_hdrfiles = gtmcrypt_util.h gtmcrypt_interface.h
 crypt_srcfiles = gtmcrypt_ref.c gtmcrypt_pk_ref.c gtmcrypt_dbk_ref.c gtmcrypt_sym_ref.c
-crypt_objfiles = gtmcrypt_ref.o gtmcrypt_pk_ref.o gtmcrypt_dbk_ref.o gtmcrypt_sym_ref.o
-all_crypt_objfiles = $(crypt_objfiles)
-
-tls_srcfiles = gtm_tls_impl.c gtm_tls_impl.h gtm_tls_interface.h
-tls_objfiles = gtm_tls_impl.o
-
-all_objfiles = $(all_crypt_objfiles) $(tls_objfiles) maskpass.o gtmcrypt_util.o gtmcrypt_util_syslib.o
-
-all: libgtmcryptutil.so maskpass gcrypt openssl gtmtls
-	rm -f $(crypt_objfiles) maskpass.o
-
-gtmcrypt_util.o: gtmcrypt_util.c
-	$(CC) $(CFLAGS) $(default_thirdparty_CFLAGS) $^
-
-# Rules for building libgtmcryptutil.so
-libgtmcryptutil.so: gtmcrypt_util.o
-	$(LD) $^ $(LDSHR) $(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
-
-# Rules for building maskpass
-maskpass.o: maskpass.c
-	$(CC) $(CFLAGS) $^
-
-# Since maskpass is a standalone utility and doesn't depend on functions like `gtm_malloc' and `gtm_free' for memory allocation,
-# build gtmcrypt_util.c with -DUSE_SYSLIB_FUNCS.
-gtmcrypt_util_syslib.o: gtmcrypt_util.c
-	$(CC) $(CFLAGS) -DUSE_SYSLIB_FUNCS $(default_thirdparty_CFLAGS) -o $@ $^
-
-# Since maskpass is a standalone utility, link it with gtmcrypt_utils_syslib.o instead of libgtmcryptutil.so. This allows maskpass
-# to be run without the need for the user setting LD_LIBRARY_PATH/LIBPATH to load libgtmcryptutil.so.
-maskpass: maskpass.o gtmcrypt_util_syslib.o
-	$(LD) $(LDFLAGS) maskpass $^ $(default_thirdparty_LDFLAGS)
-
-# Rules for building libgtmtls.so
-gtm_tls_impl.o: gtm_tls_impl.c
-	$(CC) $(CFLAGS) $<
-
-gtmtls: gtm_tls_impl.o libgtmcryptutil.so
-	$(LD) $< $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) lib$@.so -lssl $(COMMON_LIBS)
-
-# Rules for building all supported variations of encryption libraries. These again point to the specific ones.
-gcrypt: gcrypt_AES256CFB
-
-openssl: openssl_AES256CFB openssl_BLOWFISHCFB
-
-# Rules for building specific encryption libraries.
-gcrypt_AES256CFB: $(crypt_srcfiles) libgtmcryptutil.so
-	$(CC) $(CFLAGS) -DUSE_GCRYPT -DUSE_AES256CFB $(gcrypt_nofips_flag) $(crypt_srcfiles)
-	$(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lgcrypt -lgpgme -lgpg-error $(COMMON_LIBS)
-
-openssl_AES256CFB: $(crypt_srcfiles) libgtmcryptutil.so
-	$(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_AES256CFB $(crypt_srcfiles)
-	$(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
-
-openssl_BLOWFISHCFB: $(crypt_srcfiles) libgtmcryptutil.so
-	$(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_BLOWFISHCFB $(crypt_srcfiles)
-	$(LD) $(crypt_objfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) libgtmcrypt_$@.so -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
-
-# The below rule is useful when the user wants to [re]build a specific target (one of gcrypt_AES256CFB, openssl_AES256CFB or
-# openssl_BLOWFISHCFB).
-gtmcrypt: $(thirdparty)_$(algo)
-
-
-# install, uninstall and cleanup rules.
-install:
-	rm -f $(all_objfiles)
-	mv *.so $(PLUGINDIR)
-	ln -s ./$(install_targ) $(PLUGINDIR)/libgtmcrypt.so
+crypt_hrdfiles = gtmcrypt_ref.h gtmcrypt_pk_ref.h gtmcrypt_dbk_ref.h gtmcrypt_sym_ref.h gtmcrypt_interface.h
+tls_srcfiles = gtm_tls_impl.c
+tls_hdrfiles = gtm_tls_impl.h gtm_tls_interface.h
+
+all: libgtmcryptutil.so maskpass gcrypt openssl libgtmtls.so
+
+libgtmcryptutil.so: $(crypt_util_srcfiles) $(crypt_util_hdrfiles)
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) $(default_thirdparty_CFLAGS) $(crypt_util_srcfiles) $(LDSHR) $(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
+
+# Since maskpass is a standalone utility, link it (implicitly) with gtmcrypt_util.o instead of libgtmcryptutil.so. This allows
+# maskpass to be run without setting LD_LIBRARY_PATH/LIBPATH to load libgtmcryptutil.so. As a standalone utility maskpass should
+# not depend on functions like `gtm_malloc' and `gtm_free', so we are compiling the executable with -DUSE_SYSLIB_FUNCS.
+maskpass: maskpass.c $(crypt_util_srcfiles) $(crypt_util_hdrfiles)
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) -DUSE_SYSLIB_FUNCS $(default_thirdparty_CFLAGS) maskpass.c $(crypt_util_srcfiles)	\
+		$(LDFLAGS) $@ $(default_thirdparty_LDFLAGS)
+
+gcrypt: libgtmcrypt_gcrypt_AES256CFB.so
+
+libgtmcrypt_gcrypt_AES256CFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) -DUSE_GCRYPT -DUSE_AES256CFB $(gcrypt_nofips_flag) $(crypt_srcfiles) $(LDSHR)		\
+		$(RPATHFLAGS) $(LDFLAGS) $@ -lgcrypt -lgpgme -lgpg-error $(COMMON_LIBS)
+
+openssl: libgtmcrypt_openssl_AES256CFB.so libgtmcrypt_openssl_BLOWFISHCFB.so
+
+libgtmcrypt_openssl_AES256CFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_AES256CFB $(crypt_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS)	\
+		$@ -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
+
+libgtmcrypt_openssl_BLOWFISHCFB.so: $(crypt_srcfiles) $(crypt_hdrfiles) libgtmcryptutil.so
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) -DUSE_OPENSSL -DUSE_BLOWFISHCFB $(crypt_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS)	\
+	$@ -lcrypto -lgpgme -lgpg-error $(COMMON_LIBS)
+
+libgtmtls.so: $(tls_srcfiles) $(tls_hdrfiles) libgtmcryptutil.so
+	@echo ; echo "Compiling $@..."
+	$(CC) $(CFLAGS) $(tls_srcfiles) $(LDSHR) $(RPATHFLAGS) $(LDFLAGS) $@ -lssl $(COMMON_LIBS)
+
+install: all
+	@echo ; echo "Installing shared libraries to $(PLUGINDIR) and maskpass to $(PLUGINDIR)/gtmcrypt..."
+	cp -f *.so $(PLUGINDIR)
+	ln -fs ./$(install_targ) $(PLUGINDIR)/libgtmcrypt.so
+ifeq ($(NOT_IN_GTMCRYPTDIR),1)
+	cp -f maskpass $(PLUGINDIR)/gtmcrypt
+endif
 
 uninstall:
+	@echo ; echo "Uninstalling shared libraries from $(PLUGINDIR) and maskpass from $(PLUGINDIR)/gtmcrypt..."
 	rm -f $(PLUGINDIR)/*.so
 	rm -f $(PLUGINDIR)/gtmcrypt/maskpass
 
 clean:
-	rm -f $(all_objfiles)
+	@echo ; echo "Removing generated files..."
 	rm -f *.so
+ifeq ($(NOT_IN_GTMCRYPTDIR),1)
 	rm -f maskpass
+endif
diff --git a/sr_port/md5_digest2hex.h b/sr_unix/arlinkdbg.h
similarity index 53%
copy from sr_port/md5_digest2hex.h
copy to sr_unix/arlinkdbg.h
index fe3322c..e820bd0 100644
--- a/sr_port/md5_digest2hex.h
+++ b/sr_unix/arlinkdbg.h
@@ -9,13 +9,20 @@
  *								*
  ****************************************************************/
 
-#ifndef MD5_DIGEST2HEX_INCLUDED
-#define MD5_DIGEST2HEX_INCLUDED
+/* Header file to control debugging for autorelink */
+#ifndef ARLINKDBG_H
+#define ARLINKDBG_H
 
-#include "md5hash.h"
+/* To enable debugging macros (output to console) uncomment the following #define */
+/*#define DEBUG_ARLINK*/
+#ifdef DEBUG_ARLINK
+# define DBGARLNK(x) DBGFPF(x)
+# define DBGARLNK_ONLY(x) x
+# include "gtm_stdio.h"
+# include "gtmio.h"
+#else
+# define DBGARLNK(x)
+# define DBGARLNK_ONLY(x)
+#endif
 
-#define MD5_HEXSTR_LENGTH	33
-
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH]);
-
-#endif /* MD5_DIGEST2HEX_INCLUDED */
+#endif
diff --git a/sr_unix/auto_zlink.c b/sr_unix/auto_zlink.c
index 9214738..d444b35 100644
--- a/sr_unix/auto_zlink.c
+++ b/sr_unix/auto_zlink.c
@@ -46,13 +46,6 @@ rhdtyp	*auto_zlink(mach_inst *pc, lnr_tabent ***line)
 	rhdtyp		*rhead;
 	urx_rtnref	*rtnurx;
 
-#	ifdef USHBIN_SUPPORTED
-	/* With the current autorelink multi-opcode call (OP_RHD_EXT and OP_LAB_EXT prior to actual call), auto_zlink()
-	 * isn't really at all used but this is likely to change in the next release which streamlines some of this so
-	 * for now, this routine is not being nixed.
-	 */
-	USHBIN_ONLY(assertpro(FALSE));
-#	else
 /* (ASSUMPTION)
  * The instructions immediately preceding the current mpc form a transfer table call.
  *	There will be two arguments to this call:
@@ -90,28 +83,27 @@ rhdtyp	*auto_zlink(mach_inst *pc, lnr_tabent ***line)
 	if (azl_geturxrtn((char *)A_rtnhdr, &rname, &rtnurx))
 	{
 		assert(rname.len <= MAX_MIDENT_LEN);
-		assert(0 != rname.addr);
+		assert(NULL != 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_buff.c, rname.addr, rname.len);
                 rname.addr = rname_buff.c;
-		assert(0 != rtnurx);
+		assert(NULL != rtnurx);
 		assert(azl_geturxlab((char *)A_labaddr, rtnurx));
-		assert(0 == find_rtn_hdr(&rname));
+		assert(NULL == 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)))
+		op_zlink(&rtn, NULL);
+		if (NULL != (rhead = find_rtn_hdr(&rname)))
 		{	/* Pull the linkage table reference out and return it to caller */
 			*line = (lnr_tabent **)(A_labaddr->ext_ref);
-			if (0 == *line)
+			if (NULL == *line)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LABELUNKNOWN);
 			return rhead;
 		}
 	}
 	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ROUTINEUNKNOWN);
-#	endif		/* ifdef USHBIN_SUPPORTED */
 	return NULL;	/* Compiler happiness phase */
 }
diff --git a/sr_unix/bin_load.c b/sr_unix/bin_load.c
index ca1b9e4..9872d27 100644
--- a/sr_unix/bin_load.c
+++ b/sr_unix/bin_load.c
@@ -113,22 +113,22 @@ error_def(ERR_RECLOAD);
 
 #define	DEFAULT_SN_HOLD_BUFF_SIZE MAX_IO_BLOCK_SIZE
 
-#define KILL_INCMP_SN_IF_NEEDED(GVNH_REG)									\
-{														\
-	gd_region	*dummy_reg;										\
-														\
-	if (!sn_incmp_gbl_already_killed)									\
-	{													\
-		COPY_KEY(sn_savekey, gv_currkey);								\
-		COPY_KEY(gv_currkey, sn_gvkey);									\
-		/* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH				\
-		 * (e.g. setting gv_cur_region for spanning globals).						\
-		 */												\
-		GV_BIND_SUBSNAME_IF_GVSPAN(GVNH_REG, gd_header, gv_currkey, dummy_reg);		\
-		bin_call_db(BIN_KILL, 0, 0);									\
-		COPY_KEY(gv_currkey, sn_savekey);								\
-		sn_incmp_gbl_already_killed = TRUE;								\
-	}													\
+#define KILL_INCMP_SN_IF_NEEDED(GVNH_REG)											\
+{																\
+	gd_region	*dummy_reg;												\
+																\
+	if (!sn_incmp_gbl_already_killed)											\
+	{															\
+		COPY_KEY(sn_savekey, gv_currkey);										\
+		COPY_KEY(gv_currkey, sn_gvkey);											\
+		/* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH						\
+		 * (e.g. setting gv_cur_region for spanning globals).								\
+		 */														\
+		GV_BIND_SUBSNAME_IF_GVSPAN(GVNH_REG, gd_header, gv_currkey, dummy_reg);						\
+		bin_call_db(BIN_KILL, 0, 0);											\
+		COPY_KEY(gv_currkey, sn_savekey);										\
+		sn_incmp_gbl_already_killed = TRUE;										\
+	}															\
 }
 
 #define DISPLAY_INCMP_SN_MSG													\
@@ -221,7 +221,7 @@ void zwr_out_print(char * buff, int bufflen)
 	FPRINTF(stderr,"\n");
 }
 
-void bin_load(uint4 begin, uint4 end)
+void bin_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len)
 {
 	unsigned char		*ptr, *cp1, *cp2, *btop, *gvkey_char_ptr, *tmp_ptr, *tmp_key_ptr, *c, *ctop, *ptr_base;
 	unsigned char		hdr_lvl, src_buff[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ],
@@ -231,9 +231,10 @@ void bin_load(uint4 begin, uint4 end)
 	int			len;
 	int			current, last, length, max_blk_siz, max_key, status;
 	int			tmp_cmpc, sn_chunk_number, expected_sn_chunk_number = 0, sn_hold_buff_pos, sn_hold_buff_size;
-	uint4			iter, max_data_len, max_subsc_len, key_count, gblsize;
-	ssize_t			rec_count, global_key_count, subsc_len,extr_std_null_coll, last_sn_error_offset=0,
-					file_offset_base=0, file_offset=0;
+	uint4			max_data_len, max_subsc_len, gblsize;
+	ssize_t			subsc_len, extr_std_null_coll;
+	gtm_uint64_t		iter, key_count, rec_count, tmp_rec_count, global_key_count;
+	off_t			last_sn_error_offset = 0, file_offset_base = 0, file_offset = 0;
 	boolean_t		need_xlation, new_gvn, utf8_extract;
 	boolean_t		is_hidden_subscript, ok_to_put = TRUE, putting_a_sn = FALSE, sn_incmp_gbl_already_killed = FALSE;
 	rec_hdr			*rp, *next_rp;
@@ -260,6 +261,12 @@ void bin_load(uint4 begin, uint4 end)
 	assert(4 == SIZEOF(coll_hdr));
 	gvinit();
 	v.mvtype = MV_STR;
+	file_offset_base = 0;
+	/* line1_ptr,line1_len were initialized as part of get_file_format using reads of the binary extract file which
+	 * did not go through file_input_bin_get. So initialize the internal static structures that file_input_bin_get
+	 * maintains as if that read happened through it. This will let us finish reading the binary extract header line.
+	 */
+	file_input_bin_init(line1_ptr, line1_len);
 	len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base, DO_RTS_ERROR_FALSE);
 	if (0 >= len)
 	{
@@ -329,8 +336,8 @@ void bin_load(uint4 begin, uint4 end)
 #	ifdef GTM_CRYPT
 	if ('7' <= hdr_lvl)
 	{
-		encrypted_hash_array_len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base,
-				DO_RTS_ERROR_TRUE);
+		encrypted_hash_array_len = file_input_bin_get((char **)&ptr, &file_offset_base,
+								(char **)&ptr_base, DO_RTS_ERROR_TRUE);
 		encrypted_hash_array_ptr = malloc(encrypted_hash_array_len);
 		memcpy(encrypted_hash_array_ptr, ptr, encrypted_hash_array_len);
 		n_index = encrypted_hash_array_len / GTMCRYPT_HASH_LEN;
@@ -368,7 +375,7 @@ void bin_load(uint4 begin, uint4 end)
 		if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base, DO_RTS_ERROR_TRUE)))
 		{
 			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
-			util_out_print("Error reading record number: !UL\n", TRUE, iter);
+			util_out_print("Error reading record number: !@UQ\n", TRUE, &iter);
 			mupip_error_occurred = TRUE;
 			return;
 		} else if (len == SIZEOF(coll_hdr))
@@ -383,6 +390,7 @@ void bin_load(uint4 begin, uint4 end)
 	max_data_len = 0;
 	max_subsc_len = 0;
 	global_key_count = key_count = 0;
+	GTM_WHITE_BOX_TEST(WBTEST_FAKE_BIG_KEY_COUNT, key_count, 4294967196U); /* (2**32)-100=4294967196 */
 	rec_count = begin - 1;
 	extr_collseq = db_collseq = NULL;
 	need_xlation = FALSE;
@@ -405,9 +413,10 @@ void bin_load(uint4 begin, uint4 end)
 			break;
 		if (mu_ctrlc_occurred)
 		{
-			util_out_print("!AD:!_  Key cnt: !UL  max subsc len: !UL  max data len: !UL", TRUE,
-				LEN_AND_LIT("LOAD TOTAL"), key_count, max_subsc_len, max_data_len);
-			util_out_print("Last LOAD record number: !UL", TRUE, key_count ? (rec_count - 1) : 0);
+			util_out_print("!AD:!_  Key cnt: !@UQ  max subsc len: !UL  max data len: !UL", TRUE,
+				LEN_AND_LIT("LOAD TOTAL"), &key_count, max_subsc_len, max_data_len);
+			tmp_rec_count = key_count ? (rec_count - 1) : 0;
+			util_out_print("Last LOAD record number: !@UQ", TRUE, &tmp_rec_count);
 			mu_gvis();
 			util_out_print(0, TRUE);
 			mu_ctrlc_occurred = FALSE;
@@ -458,7 +467,7 @@ void bin_load(uint4 begin, uint4 end)
 			 */
 			if (mupip_error_occurred)
 			{
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, rec_count);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &rec_count);
 				ONERROR_PROCESS;
 			}
 			max_key = gvnh_reg->gd_reg->max_key_size;
@@ -817,9 +826,10 @@ void bin_load(uint4 begin, uint4 end)
 	if (NULL != sn_hold_buff)
 		free(sn_hold_buff);
 	file_input_close();
-	util_out_print("LOAD TOTAL!_!_Key Cnt: !UL  Max Subsc Len: !UL  Max Data Len: !UL", TRUE, key_count, max_subsc_len,
+	util_out_print("LOAD TOTAL!_!_Key Cnt: !@UQ  Max Subsc Len: !UL  Max Data Len: !UL", TRUE, &key_count, max_subsc_len,
 			max_data_len);
-	util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (rec_count - 1) : 0);
+	tmp_rec_count = key_count ? (rec_count - 1) : 0;
+	util_out_print("Last LOAD record number: !@UQ\n", TRUE, &tmp_rec_count);
 	if (mu_ctrly_occurred)
 	{
 		gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LOADCTRLY);
diff --git a/sr_unix/buildaux.csh b/sr_unix/buildaux.csh
index 281ac7b..67ed94f 100644
--- a/sr_unix/buildaux.csh
+++ b/sr_unix/buildaux.csh
@@ -27,6 +27,7 @@ set buildaux_status = 0
 set dollar_sign = \$
 set mach_type = `uname -m`
 set platform_name = `uname | sed 's/-//g' | tr '[A-Z]' '[a-z]'`
+set host=$HOST:r:r:r
 
 if ( $1 == "" ) then
 	@ buildaux_status++
@@ -485,7 +486,7 @@ if ( $buildaux_ftok == 1 ) then
 		set aix_loadmap_option = "-bcalls:$gtm_map/ftok.loadmap -bmap:$gtm_map/ftok.loadmap -bxref:$gtm_map/ftok.loadmap"
 	endif
 	gt_ld $gt_ld_options $aix_loadmap_option ${gt_ld_option_output}$3/ftok -L$gtm_obj $gtm_obj/ftok.o \
-			$gt_ld_sysrtns -lmumps $gt_ld_extra_libs $gt_ld_syslibs >& $gtm_map/ftok.map
+			$gt_ld_sysrtns -lmupip -lmumps -lstub $gt_ld_extra_libs $gt_ld_syslibs >& $gtm_map/ftok.map
 	if ( $status != 0  ||  ! -x $3/ftok ) then
 		@ buildaux_status++
 		echo "buildaux-E-linkftok, Failed to link ftok (see ${dollar_sign}gtm_map/ftok.map)" \
@@ -566,16 +567,6 @@ if ($buildaux_gtmcrypt == 1) then
 		else
 			set make = "make"
 		endif
-		# libssl.so isn't available on pfloyd. Skip building SSL/TLS reference implementation library on pfloyd. This is
-		# okay since pfloyd is AIX 5.3 which isn't a supported AIX version anyways.
-		set host=$HOST:r:r:r
-		if ($host !~ pfloyd) then
-			$make gtmtls image=$plugin_build_type
-			if ($status) then
-				@ buildaux_status++
-				echo "buildaux-E-tls, failed to build libgtmtls.so." >> $gtm_log/error.${gtm_exe:t}.log
-			endif
-		endif
 		# On tuatara, atlhxit1 and atlhxit2 Libgcrypt version is too low to support FIPS mode. Add necessary flags to
 		# Makefile to tell the plugin to build without FIPS support.
 		if ($host =~ {tuatara,atlhxit1,atlhxit2}) then
@@ -583,27 +574,6 @@ if ($buildaux_gtmcrypt == 1) then
 		else
 			set fips_flag = ""
 		endif
-		# Build all possible encryption libraries based on what encryption libraries are supported in this platform.
-		foreach supported_lib ($supported_list)
-			foreach algorithm ("AES256CFB" "BLOWFISHCFB")
-				if ("gcrypt" == "$supported_lib" && "BLOWFISHCFB" == "$algorithm") continue
-				echo "####### Building encryption plugin using $supported_lib with $algorithm algorithm #########"
-				$make gtmcrypt image=$plugin_build_type thirdparty=$supported_lib algo=$algorithm $fips_flag
-				if ($status) then
-					@ buildaux_status++
-					echo "buildaux-E-libgtmcrypt, failed to build gtmcrypt and/or helper scripts."	\
-									>> $gtm_log/error.${gtm_exe:t}.log
-				endif
-				echo ""
-			end
-		end
-		# Now that the individual libraries are built, go ahead and build the maskpass
-		$make maskpass
-		if ($status) then
-			@ buildaux_status++
-			echo "buildaux-E-maskpass, failed to build maskpass." >> $gtm_log/error.${gtm_exe:t}.log
-		endif
-		#
 		if ($gtm_verno =~ V[4-8]*) then
 			# For production builds don't do any randomizations.
 			set algorithm = "AES256CFB"
@@ -613,32 +583,39 @@ if ($buildaux_gtmcrypt == 1) then
 				set encryption_lib = "gcrypt"
 			endif
 		else
-			# Now that we've built "possibly" more than one encryption library, choose one configuration (based on
-			# third-party library and algorithm) randomly and install that.
+			# Randomly choose one configuration based on third-party library and algorithm.
 			set rand = `echo $#supported_list | awk '{srand() ; print 1+int(rand()*$1)}'`
 			set encryption_lib = $supported_list[$rand]
 			if ("gcrypt" == "$encryption_lib") then
 				# Force AES as long as the plugin is linked against libgcrypt
 				set algorithm = "AES256CFB"
 			else
-				# OpenSSL, V9* build. Go ahead and randomize the algorithm
-				# increase probability of AES256CFB, the industry standard and the one we officially support
+				# OpenSSL, V9* build. Go ahead and randomize the algorithm. Increase the probability of AES256CFB,
+				# the industry standard and the one we officially support.
 				set algorithms = ("AES256CFB" "AES256CFB" "BLOWFISHCFB")
 				set rand = `echo $#algorithms | awk '{srand() ; print 1+int(rand()*$1)}'`
 				set algorithm = $algorithms[$rand]
 			endif
 		endif
-		$make install thirdparty=$encryption_lib algo=$algorithm
+		# Build and install all encryption libraries and executables.
+		$make install algo=$algorithm image=$plugin_build_type thirdparty=$encryption_lib $fips_flag
+		if ($status) then
+			@ buildaux_status++
+			echo "buildaux-E-libgtmcrypt, failed to install libgtmcrypt and/or helper scripts"	\
+						>> $gtm_log/error.${gtm_exe:t}.log
+		endif
+		# Remove temporary files.
+		$make clean
 		if ($status) then
 			@ buildaux_status++
-			echo "buildaux-E-libgtmcrypt, failed to install libgtmcrypt and/or helper scripts"		\
+			echo "buildaux-E-libgtmcrypt, failed to clean libgtmcrypt and/or helper scripts"	\
 						>> $gtm_log/error.${gtm_exe:t}.log
 		endif
 		# Create the one time gpgagent.tab file.
 		echo "$gtm_dist_plugin/libgtmcryptutil.so" >&! $gtm_dist_plugin/gpgagent.tab
 		echo "unmaskpwd: gtm_status_t gc_mask_unmask_passwd(I:gtm_string_t*,O:gtm_string_t*[512])"	\
-							>>&! $gtm_dist_plugin/gpgagent.tab
-		#
+						>>&! $gtm_dist_plugin/gpgagent.tab
+
 		popd >&! /dev/null
 	endif
 endif
diff --git a/sr_unix/callintogtmxfer.c b/sr_unix/callintogtmxfer.c
index ea620a2..5af0b8c 100644
--- a/sr_unix/callintogtmxfer.c
+++ b/sr_unix/callintogtmxfer.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -18,6 +18,7 @@
 
 #include "callintogtmxfer.h"
 #include "gt_timer.h"
+#include "have_crit.h"
 
 typedef	int	(*int_fptr)();
 
@@ -51,7 +52,7 @@ void init_callin_functable(void)
 {
 	unsigned char 	*env_top, *address_top;
 	uint4 		address_len;
-	int		save_errno;
+	int		save_errno, status;
 
 	address_top = GTM64_ONLY(i2ascl)NON_GTM64_ONLY(i2asc)(gtmvectortable_address, (UINTPTR_T)(&callintogtm_vectortable[0]));
 	*address_top = '\0';
@@ -60,9 +61,10 @@ void init_callin_functable(void)
 	MEMCPY_LIT(env_top, GTM_CALLIN_START_ENV);
 	memcpy((env_top + strlen(GTM_CALLIN_START_ENV)), gtmvectortable_address, address_len);
 	*(env_top + strlen(GTM_CALLIN_START_ENV) + address_len) = '\0';
-	if (PUTENV((char *)gtmvectortable_env))
+	PUTENV(status, (char *)gtmvectortable_env);
+	if (status)
 	{
 		save_errno = errno;
-		rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno);
 	}
 }
diff --git a/sr_unix/ce_substitute.c b/sr_unix/ce_substitute.c
index 3f7f8f6..6f098e7 100644
--- a/sr_unix/ce_substitute.c
+++ b/sr_unix/ce_substitute.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -14,7 +14,7 @@
 #include "comp_esc.h"
 
 GBLREF unsigned char *source_buffer;
-GBLREF short int source_column;
+GBLREF int   source_column;
 GBLREF char *lexical_ptr;
 GBLREF struct ce_sentinel_desc	*ce_def_list;
 
diff --git a/sr_unix/cli.h b/sr_unix/cli.h
index a488100..313e8dd 100644
--- a/sr_unix/cli.h
+++ b/sr_unix/cli.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -17,7 +17,7 @@
  * Parser include file
  * -----------------------------------------------------------
  */
-#define	MAX_PARMS	5	/* Maximum parameters on commands line */
+#define	MAX_PARMS	1024	/* Maximum parameters on command line */
 
 #define MAX_CMD_LEN	25	/* Max Command name string length */
 #define MAX_OPT_LEN	25	/* Max Option name string length */
@@ -90,7 +90,7 @@ typedef struct cmd_parm_tag {
 							0 - disallowed,
 							1 - optional
 							2 - required */
-	unsigned 	max_parms : 3;		/* Max. # of parameters allowed */
+	unsigned short	max_parms;		/* Max. # of parameters allowed */
 	unsigned 	negatable : 1;		/* Negatable flag  */
 	unsigned 	val_type : 2;		/* Value Type
 							VAL_N_A - type not applicable
diff --git a/sr_unix/cli_parse.c b/sr_unix/cli_parse.c
index 62d677c..091c935 100644
--- a/sr_unix/cli_parse.c
+++ b/sr_unix/cli_parse.c
@@ -298,7 +298,7 @@ int 	parse_arg(CLI_ENTRY *pcmd_parms, int *eof)
 		cli_get_string_token(eof);
 		if (TREF(parms_cnt) >= gpcmd_verb->max_parms)
 		{
-			SNPRINTF(cli_err_str, MAX_CLI_ERR_STR, "Too many parameters ");
+			SNPRINTF(cli_err_str, MAX_CLI_ERR_STR, "Too many parameters");
 			return (-1);
 		}
 		TAREF1(parm_str_len, TREF(parms_cnt)) = strlen(cli_token_buf) + 1;
diff --git a/sr_unix/comlist.csh b/sr_unix/comlist.csh
index 3d4a0a7..9b1138a 100644
--- a/sr_unix/comlist.csh
+++ b/sr_unix/comlist.csh
@@ -326,16 +326,6 @@ if ( "$HOSTOS" == "OS/390disable" ) then
 	cp $gtm_inc/gtm_stat.h .
 endif
 
-
-if ( "$HOSTOS" == "SunOS" ) then
-	# Support for RPC implementation of DAL's and ZCALL's.
-	# gtm_descript.h is already copied.
-	cp $gtm_inc/gtmidef.h .
-endif
-
-cp $gtm_pct/*.hlp .
-
-
 #	If this is a test version not being built in $gtm_exe
 #	(see value of $3), then make sure ./obj and ./map exist.
 if ( ! -d ./obj ) then
@@ -654,16 +644,16 @@ rm -f obj/gengtmdeftypes.log* >& /dev/null
 rm -f GTMDefinedTypesInit.m >& /dev/null
 echo "Generating GTMDefinedTypesInit.m"
 if ($?work_dir) then
-	if (-e $work_dir/tools/cms_tools/gengtmdeftypes.csh) then
+	if (-e $work_dir/tools/cms_tools/builddefinedtypes/gengtmdeftypes.csh) then
 		echo "Using gengtmdeftypes.csh from $work_dir"
-		$work_dir/tools/cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+		$work_dir/tools/cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
 		@ savestatus = $status
 	else
-		$cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+		$cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
 		@ savestatus = $status
 	endif
 else
-	$cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+	$cms_tools/builddefinedtypes/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
 	@ savestatus = $status
 endif
 if ((0 != $savestatus) || (! -e GTMDefinedTypesInit.m)) then
@@ -739,32 +729,11 @@ if ($status) then
 endif
 
 # Create the GT.M/GDE/MUPIP/DSE/LKE help databases
-foreach hlp (*.hlp)
-	set hlp_status = 0
-	set prefix=${hlp:r}
-	if ("${prefix}" == "mumps") set prefix="gtm"
-	setenv gtmgbldir $gtm_dist/${prefix}help.gld
-	gde <<GDE_in_help
-Change -segment DEFAULT	-block=2048	-file=\$gtm_dist/${prefix}help.dat
-Change -region DEFAULT	-record=1020	-key=255
-GDE_in_help
-
-	if ($status) @ hlp_status++
-	mupip create
-	if ($status) @ hlp_status++
-	gtm <<GTM_in_gtmhelp
-Do ^GTMHLPLD
-$gtm_dist/${hlp}
-Halt
-GTM_in_gtmhelp
-
-	if ($status) @ hlp_status++
-	if ($hlp_status) then
-		@ comlist_status = $comlist_status + $hlp_status
-		echo "comlist-E-hlp, Error processing $hlp file" >> $errorlog
-	endif
-
-end
+$gtm_tools/generate_help.csh $gtm_pct $errorlog
+if ($status) then
+	@ comlist_status++
+	echo "comlist-E-hlp, Error generating hlp databases" >> $errorlog
+endif
 
 chmod 775 *	# do not check $status here because we know it will be 1 since "gtmsecshr" permissions cannot be changed.
 
diff --git a/sr_unix/comp_lits.c b/sr_unix/comp_lits.c
index 3f7b89b..23b8a8d 100644
--- a/sr_unix/comp_lits.c
+++ b/sr_unix/comp_lits.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2009 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -14,6 +14,7 @@
 #include <rtnhdr.h>
 #include "mdq.h"
 #include "stringpool.h"
+#include "obj_file.h"
 
 GBLREF mliteral		literal_chain;
 GBLREF spdesc		stringpool;
@@ -24,14 +25,18 @@ GBLDEF uint4		lits_text_size, lits_mval_size;
 
 void comp_lits(rhdtyp *rhead)
 {
-  	size_t		offset;
-	uint4		cnt;
-	uint4 		align_pad;
-	mliteral	*p;
+  	size_t			offset;
+	uint4			cnt;
+	uint4 			align_pad;
+	mliteral		*p;
+	struct linkage_entry	*linkagep;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	/* Literal text pool is formed in stringpool except for the file name/path of the
 	 * source module and routine name which will be emitted by emit_literals immediately
-	 * following the literal text pool and is considered part of that text pool.*/
+	 * following the literal text pool and is considered part of that text pool.
+	 */
 	offset = (stringpool.free - stringpool.base);
 	offset += PADLEN(offset, NATIVE_WSIZE);
 	rhead->src_full_name.len = source_name_len;
@@ -42,6 +47,12 @@ void comp_lits(rhdtyp *rhead)
 	rhead->routine_name.addr = (char *)offset;
 	offset += routine_name.len;
 	offset += PADLEN(offset, NATIVE_WSIZE);
+	for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+	{	/* Compute space for linkage name usage (symbol names associated with each linkage symbol) */
+		linkagep->lit_offset = offset;
+		offset += linkagep->symbol->name_len - 1;
+		offset += PADLEN(offset, NATIVE_WSIZE);
+	}
 	lits_text_size = UINTCAST(offset);
 	offset = 0;
 	dqloop(&literal_chain, que, p)
diff --git a/sr_unix/dbcertify_signal_handler.c b/sr_unix/dbcertify_signal_handler.c
index d28368d..c0de6ef 100644
--- a/sr_unix/dbcertify_signal_handler.c
+++ b/sr_unix/dbcertify_signal_handler.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -78,9 +78,9 @@ error_def(ERR_KRNLKILL);
 
 void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 {
-	boolean_t	exit_now;
+	boolean_t		dbc_critical, exit_now;
 	gtm_sigcontext_t	*context_ptr;
-	void		(*signal_routine)();
+	void			(*signal_routine)();
 
 	/* Save parameter value in global variables for easy access in core */
 	dont_want_core = FALSE;		/* (re)set in case we recurse */
@@ -119,11 +119,12 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 				}
 				++core_in_progress;
 				DUMP_CORE;
-				GTMASSERT;
+				assertpro(FALSE);
 			default:
 				;
 		}
 	}
+	dbc_critical = ((NULL != psa_gbl) && psa_gbl->dbc_critical);
 	switch(sig)
 	{
 		case SIGINT:
@@ -132,7 +133,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 			/* If nothing pending AND we have crit or already in exit processing, wait to
 			 * invoke shutdown.
 			 */
-			if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+			if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
 			{
 				SET_FORCED_EXIT_STATE;
 				exit_state++;		/* Make exit pending, may still be tolerant though */
@@ -165,10 +166,10 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 					break;
 				default:
 					exit_state = EXIT_IMMED;
-					GTMASSERT;
+					assertpro(FALSE);
 			}
 			/* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */
-			if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+			if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
 			{
 				SET_FORCED_EXIT_STATE;
 				exit_state++;		/* Make exit pending, may still be tolerant though */
@@ -215,7 +216,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 		case SIGDANGER:
 			forced_exit_err = ERR_KRNLKILL;
 			/* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */
-			if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+			if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
 			{
 				SET_FORCED_EXIT_STATE;
 				exit_state++;		/* Make exit pending, may still be tolerant though */
@@ -242,7 +243,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 					/* This signal was SENT to us so it can wait until we are out of crit to cause an exit */
 					forced_exit_err = ERR_KILLBYSIGUINFO;
 					/* If nothing pending AND we have crit or already exiting, wait to invoke shutdown */
-					if ((EXIT_PENDING_TOLERANT >= exit_state) && (psa_gbl->dbc_critical || exit_handler_active))
+					if ((EXIT_PENDING_TOLERANT >= exit_state) && (dbc_critical || exit_handler_active))
 					{
 						SET_FORCED_EXIT_STATE;
 						exit_state++;		/* Make exit pending, may still be tolerant though */
@@ -281,7 +282,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 					break;
 				default:
 					exit_state = EXIT_IMMED;
-					GTMASSERT;
+					assertpro(FALSE);
 			}
 			if (0 != signal_info.sig_err)
 			{
@@ -297,7 +298,7 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
 		gtm_fork_n_core();
 	}
 	/* As on VMS, a mupip stop does not drive the condition handlers unless we are in crit */
-	if ((psa_gbl->dbc_critical || SIGTERM != exi_condition) && CHANDLER_EXISTS)
+	if ((dbc_critical || (SIGTERM != exi_condition)) && CHANDLER_EXISTS)
 		DRIVECH(exi_condition);
 
 	assert((EXIT_IMMED <= exit_state) || !exit_handler_active);
diff --git a/sr_unix/do_shmat.c b/sr_unix/do_shmat.c
index f74a1f5..a0fbc44 100644
--- a/sr_unix/do_shmat.c
+++ b/sr_unix/do_shmat.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2004 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -17,6 +17,9 @@
 #include "mdef.h"
 
 #include <sys/shm.h>
+#include <sys/mman.h>
+#include <errno.h>
+
 #ifndef __MVS__
 #include <sys/sysmacros.h>
 #endif
@@ -25,14 +28,44 @@
 
 #include "do_shmat.h"
 
-GBLREF	int4		gtm_shmflags;	/* Flags to OR into supplied flags */
-
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg)
+void *do_shmat(int4 shmid, const void *shm_base, int4 shmflg)
 {
-#ifdef __sparc
-	return(shmat((int)shmid, shmaddr, shmflg | gtm_shmflags | SHM_SHARE_MMU));
-#else
-	return(shmat((int)shmid, shmaddr, shmflg | gtm_shmflags));
-#endif
+#	ifdef __sparc
+	return(shmat((int)shmid, shm_base, shmflg | SHM_SHARE_MMU));
+#	else
+	return(shmat((int)shmid, shm_base, shmflg));
+#	endif
 }
 
+/* This is do_shmat + capability to execute code from shared memory.
+ * Currently (Oct 2014), only newer Linuxes supports SHM_EXEC bit. Other platforms dont seem to have this option.
+ * So we use mprotect (additional system call) there to implement this requirement.
+ * Until SHM_EXEC is not available on all POSIX platforms that GT.M is built/supported on, we need the mprotect code.
+ */
+void *do_shmat_exec_perm(int4 shmid, size_t shm_size, int *save_errno)
+{
+	int4	shmflg;
+	void	*addr;
+
+#	if defined(SHM_EXEC)
+	shmflg = SHM_EXEC;
+#	else
+	shmflg = 0;
+#	endif
+	addr = do_shmat(shmid, NULL, shmflg);
+	if (-1 == (sm_long_t)addr)
+	{
+		*save_errno = errno;
+		return addr;
+	}
+#	if !defined(SHM_EXEC)
+	if (-1 == mprotect(addr, shm_size, PROT_READ | PROT_WRITE | PROT_EXEC))
+	{
+		*save_errno = errno;
+		assert(FALSE);
+		SHMDT(addr);
+		addr = (void *)-1;
+	}
+#	endif
+	return addr;
+}
diff --git a/sr_unix/do_shmat.h b/sr_unix/do_shmat.h
index c4143a7..f7da458 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/do_shmat.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -12,6 +12,7 @@
 #ifndef __DO_SHMAT_H__
 #define __DO_SHMAT_H__
 
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void *do_shmat(int4 shmid, const void *shm_base, int4 shmflg);
+void *do_shmat_exec_perm(int4 shmid, size_t shm_size, int *save_errno);
 
 #endif
diff --git a/sr_unix/dollarh.c b/sr_unix/dollarh.c
index 3a010d8..d406b30 100644
--- a/sr_unix/dollarh.c
+++ b/sr_unix/dollarh.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -20,7 +20,7 @@
 
 void dollarh(time_t intime, uint4 *days, time_t *seconds)
 {
-	uint4		tdays;
+	int4		tdays;
 	int		isdst;
 	struct tm	*ttime;
 	time_t		mktime_ret;
@@ -40,22 +40,17 @@ void dollarh(time_t intime, uint4 *days, time_t *seconds)
 	 * is to block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) during the function and then restore them
 	 * at the end. [C9D06-002271] [C9I03-002967].
 	 */
-	GTM_LOCALTIME(ttime, &intime);		/* represent intime as local time in case of offsets from UCT other than hourly */
+	GTM_LOCALTIME(ttime, &intime);		/* represent intime as local time in case of offsets from UTC other than hourly */
 	*seconds  = (time_t)(ttime->tm_hour * HOUR) + (ttime->tm_min * MINUTE) + ttime->tm_sec;
 	isdst = ttime->tm_isdst;
-	GTM_GMTIME(ttime, &intime);			/* represent intime as UCT */
+	GTM_GMTIME(ttime, &intime);		/* represent intime as UTC */
 	ttime->tm_isdst = isdst; 		/* use GTM_LOCALTIME to tell mktime whether daylight savings needs to be applied */
 	GTM_MKTIME(mktime_ret, ttime);
 	assert((time_t)-1 != mktime_ret);
-	tdays = (uint4)((intime + (time_t)difftime(intime, mktime_ret)) / ONEDAY) + DAYS;	/* adjust relative to UTC */
-	*days = tdays;				/* use temp local in case the caller has overlapped arguments */
-	/* Assert that $H always moves forward. The only exception is a negative time adjustment due to DST change.
-	 * Do asserts AFTER unblocking signals as otherwise assert failures could hang and/or result in no cores.
-	 * DSE and MUPIP use this function to potentially display times in the past (e.g. in DSE DUMP -FILE,
-	 * MUPIP JOURNAL EXTRACT) so restrict this assert to the runtime for now.
-	 */
-	assert(!IS_GTM_IMAGE || ((*days == old_days) && (*seconds >= old_seconds)) || (*days > old_days)
-		|| (0 < old_isdst) && (0 == isdst));
+	/* adjust relative to UTC - have to round the other way if intime is less than or equal to the UTC offset */
+	tdays = (int4)(intime - mktime_ret);
+	tdays = (int4)(((intime + tdays - (((intime + tdays) > 0) ? 0 : (ONEDAY - 1))) / ONEDAY) + DAYS);
+	*days = (uint4)tdays;				/* use temp local in case the caller has overlapped arguments */
 	DEBUG_ONLY(old_seconds = (uint4)*seconds; old_days = *days; old_intime = intime; old_isdst = isdst;)
 	return;
 }
diff --git a/sr_unix/dsk_read.c b/sr_unix/dsk_read.c
index 13f40e2..33991ca 100644
--- a/sr_unix/dsk_read.c
+++ b/sr_unix/dsk_read.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -220,13 +220,14 @@ int4	dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
 	/* Expect t_tries to be 3 if we have crit. Exceptions: gvcst_redo_root_search (where t_tries is temporarily reset
 	 * for the duration of the redo_root_search and so we should look at the real t_tries in redo_rootsrch_ctxt),
 	 * gvcst_expand_free_subtree, REORG UPGRADE/DOWNGRADE, DSE (where we grab crit before doing the t_qread irrespective
-	 * of t_tries), forward recovery (where we grab crit before doing everything)
+	 * of t_tries), forward recovery (where we grab crit before doing everything) OR MUPIP TRIGGER -UPGRADE (where we
+	 * grab crit before doing the entire ^#t upgrade TP transaction).
 	 */
 	effective_t_tries = UNIX_ONLY( (TREF(in_gvcst_redo_root_search)) ? (TREF(redo_rootsrch_ctxt)).t_tries : ) t_tries;
 	effective_t_tries = MAX(effective_t_tries, t_tries);
 	killinprog = (NULL != ((dollar_tlevel) ? sgm_info_ptr->kip_csa : kip_csa));
 	assert(dse_running || killinprog || jgbl.forw_phase_recovery || mu_reorg_upgrd_dwngrd_in_prog
-			|| (cs_addrs->now_crit != (CDB_STAGNATE > effective_t_tries)));
+			GTMTRIG_ONLY(|| TREF(in_trigger_upgrade)) || (cs_addrs->now_crit != (CDB_STAGNATE > effective_t_tries)));
 	if (!blk_free && cs_addrs->now_crit && !dse_running && (0 == save_errno))
 	{	/* Do basic checks on GDS block that was just read. Do it only if holding crit as we could read
 		 * uninitialized blocks otherwise. Also DSE might read bad blocks even inside crit so skip checks.
diff --git a/sr_unix/errorsp.h b/sr_unix/errorsp.h
index 8a36998..8cf6f1c 100644
--- a/sr_unix/errorsp.h
+++ b/sr_unix/errorsp.h
@@ -466,4 +466,6 @@ CONDITION_HANDLER(gvcst_spr_queryget_ch);
 CONDITION_HANDLER(op_fnzpeek_ch);
 CONDITION_HANDLER(op_fnzpeek_getpool_ch);
 
+CONDITION_HANDLER(trigger_upgrade_ch);
+
 #endif
diff --git a/sr_port/lastchance3.c b/sr_unix/exi_ch.c
similarity index 62%
copy from sr_port/lastchance3.c
copy to sr_unix/exi_ch.c
index 991e2cd..3b9493b 100644
--- a/sr_port/lastchance3.c
+++ b/sr_unix/exi_ch.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -10,40 +10,28 @@
  ****************************************************************/
 
 #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;
+DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;)
 
-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)
+CONDITION_HANDLER(exi_ch)
 {
-
 	START_CH(TRUE);
 	ESTABLISH(terminate_ch);
+	exi_condition = SIGNAL;
 	if (DUMPABLE)
 	{
 		PRN_ERROR;
-		dec_err(VARLSTCNT(1) ERR_IORUNDOWN);
 		if (!SUPPRESS_DUMP)
 			DUMP_CORE;
 		PROCDIE(exi_condition);
 	}
 	REVERT;
+	DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE);
 	UNWIND(NULL, NULL);
 }
diff --git a/sr_unix/file_input.c b/sr_unix/file_input.c
index 2af5488..f9df5d9 100644
--- a/sr_unix/file_input.c
+++ b/sr_unix/file_input.c
@@ -42,10 +42,24 @@ error_def(ERR_PREMATEOF);
 static char		buff1[BUFF_SIZE];
 static char		*buff1_end;
 static char		*buff1_ptr;
-static ssize_t		buff1_ptr_file_offset;
+static off_t		buff1_ptr_file_offset;
 static char		*load_fn_ptr;
 static int		load_fn_len;
-static readonly unsigned char open_params_list[] =
+static unsigned char open_params_list_default[] =
+{
+	(unsigned char)iop_recordsize,	/* 64K enough to hold MAX_BLK_SZ */
+#	ifdef BIGENDIAN
+	(unsigned char)0, (unsigned char)0, (unsigned char)255, (unsigned char)255,
+#	else
+	(unsigned char)255, (unsigned char)255, (unsigned char)0, (unsigned char)0,
+#	endif
+	(unsigned char)iop_readonly,
+	(unsigned char)iop_m,
+	/* iop_stream not included since it is necessary only if we are opening file for write (which is not the case here) */
+	(unsigned char)iop_nowrap,
+	(unsigned char)iop_eol
+};
+static unsigned char open_params_list_rewind[] =
 {
 	(unsigned char)iop_recordsize,	/* 64K enough to hold MAX_BLK_SZ */
 #	ifdef BIGENDIAN
@@ -61,16 +75,23 @@ static readonly unsigned char open_params_list[] =
 	(unsigned char)iop_eol
 };
 
-void file_input_init(char *fn, short fn_len)
+void file_input_init(char *fn, short fn_len, open_params_flags params_flag)
 {
 	int		status;
 	mval		pars, val;
 	unsigned char	no_param = (unsigned char)iop_eol;
+	unsigned char*	open_params;
 
 	ESTABLISH(mupip_load_ch);
 	pars.mvtype = MV_STR;
-	pars.str.len = SIZEOF(open_params_list);
-	pars.str.addr = (char *)open_params_list;
+	if (params_flag & IOP_REWIND)
+	{
+		pars.str.len = SIZEOF(open_params_list_rewind);
+		pars.str.addr = (char *)open_params_list_rewind;
+	} else { /* IOP_EOL */
+		pars.str.len = SIZEOF(open_params_list_default);
+		pars.str.addr = (char *)open_params_list_default;
+	}
 	val.mvtype = MV_STR;
 	val.str.len = fn_len;
 	val.str.addr = (char *)fn;
@@ -103,7 +124,17 @@ void file_input_close(void)
 	op_close(&val, &pars);
 }
 
-int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, boolean_t do_rts_error)
+void file_input_bin_init(char *line1_ptr, int line1_len)
+{
+	assert(buff1_ptr == buff1);
+	assert(line1_len < BUFF_SIZE);
+	assert(buff1_end == buff1_ptr);
+	assert(0 == buff1_ptr_file_offset);
+	memcpy(buff1_ptr, line1_ptr, line1_len);
+	buff1_end += line1_len;
+}
+
+int file_input_bin_get(char **in_ptr, off_t *file_offset, char **buff_base, boolean_t do_rts_error)
 {
 	char	*ptr;
 	int	rd_cnt, rd_len, ret, s1;
@@ -120,8 +151,7 @@ int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, bo
 				if (do_rts_error)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PREMATEOF);
 				ret = ERR_PREMATEOF;
-			}
-			else if (-1 == rd_len)
+			} else if (-1 == rd_len)
 			{
 				if (do_rts_error)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADFILERR, 2, load_fn_len, load_fn_ptr);
@@ -192,14 +222,44 @@ int file_input_bin_read(void)
 	return rdlen;
 }
 
-int file_input_get(char **in_ptr)
+int file_input_get_xchar(char *in_ptr, int max_chars_to_read) /* uses opreadfl with a buffered getc call to read file content */
 {
-	char	*ptr, *tmp_ptr;
-	int	rd_len, s1;
-	mval	val;
-	static unsigned int mbuff_len = BUFF_SIZE;
-	unsigned int new_mbuff_len, ret_len;
-	static char *mbuff = buff1;
+	int		rd_len;
+	mval		val;
+
+	op_readfl(&val, max_chars_to_read, dollar_tlevel ? 0: NO_M_TIMEOUT);
+	rd_len = val.str.len;
+	if ((0 == rd_len) && io_curr_device.in->dollar.zeof)
+		return -1;
+	memcpy(in_ptr, val.str.addr, rd_len);
+	return rd_len;
+}
+
+int file_input_read_xchar(char *in_ptr, int max_chars_to_read) /* uses DOREADRL with read system api to read file content */
+{
+	int		rd_len;
+	io_desc		*iod;
+	d_rm_struct     *d_rm;
+
+	iod = io_curr_device.in;
+	d_rm = (d_rm_struct *)iod->dev_sp;
+	assert(NULL != d_rm);
+	DOREADRL(d_rm->fildes, in_ptr, max_chars_to_read, rd_len);
+	return rd_len;
+}
+
+/* Returns
+ *	-1 (FILE_INPUT_GET_ERROR) in case of errors,
+ *	-2 (FILE_INPUT_GET_LINE2LONG) in case line length of read becomes > input max_len (assuming max_len is non-zero)
+ */
+int file_input_get(char **in_ptr, int max_len)
+{
+	char			*ptr, *tmp_ptr;
+	int			rd_len, s1;
+	mval			val;
+	static char 		*mbuff = buff1;
+	static unsigned int	mbuff_len = BUFF_SIZE;
+	unsigned int 		new_mbuff_len, ret_len;
 
 	ESTABLISH_RET(mupip_load_ch, 0);
 	ret_len = 0;
@@ -212,28 +272,29 @@ int file_input_get(char **in_ptr)
 			REVERT;
 			if (io_curr_device.in->dollar.x)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_PREMATEOF);
-			return -1;
+			return FILE_INPUT_GET_ERROR;
 		}
-		if (mbuff_len < ret_len + rd_len)
+		if (max_len && ((ret_len + rd_len) > max_len))
+		{
+			REVERT;
+			return FILE_INPUT_GET_LINE2LONG;
+		}
+		if (mbuff_len < (ret_len + rd_len))
 		{
 			new_mbuff_len = MAX((ret_len + rd_len), (2 * mbuff_len));
 			tmp_ptr = (char *)malloc(new_mbuff_len);
 			if (NULL == tmp_ptr)
 			{
 				REVERT;
-				return -1;
+				return FILE_INPUT_GET_ERROR;
 			}
-			if (mbuff != buff1)
-			{
-				memcpy(tmp_ptr, mbuff, (ret_len));
-				free (mbuff);
-			} else
-				memcpy(tmp_ptr, buff1, (ret_len));
+			memcpy(tmp_ptr, mbuff, ret_len);
+			if (mbuff != buff1)	/* do not free static array, free all later expansions (malloc buffers) */
+				free(mbuff);
 			mbuff = tmp_ptr;
 			mbuff_len = new_mbuff_len;
-
 		}
-		memcpy((unsigned char *) (mbuff + ret_len), val.str.addr, rd_len);
+		memcpy((unsigned char *)(mbuff + ret_len), val.str.addr, rd_len);
 		ret_len += rd_len;
 		if ( !(io_curr_device.in->dollar.x) )
 		{
diff --git a/sr_unix/file_input.h b/sr_unix/file_input.h
index c8558ab..a8f1b40 100644
--- a/sr_unix/file_input.h
+++ b/sr_unix/file_input.h
@@ -12,13 +12,22 @@
 #ifndef __FILE_INPUT_INPUT_H__
 #define __FILE_INPUT_INPUT_H__
 
-void file_input_init(char *fn, short fn_len);
+#define	FILE_INPUT_GET_ERROR		-1
+#define	FILE_INPUT_GET_LINE2LONG	-2
+#define DO_RTS_ERROR_TRUE 		TRUE
+#define DO_RTS_ERROR_FALSE 		FALSE
+
+typedef enum {
+    IOP_EOL	= 0x00,
+    IOP_REWIND 	= 0x01
+} open_params_flags;
+void file_input_init(char *fn, short fn_len, open_params_flags params_flag);
 void file_input_close(void);
-int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base, boolean_t do_rts_error);
+void file_input_bin_init(char *line1_ptr, int line1_len);
+int file_input_bin_get(char **in_ptr, off_t *file_offset, char **buff_base, boolean_t do_rts_error);
 int file_input_bin_read(void);
-int file_input_get(char **in_ptr);
-
-#define DO_RTS_ERROR_TRUE TRUE
-#define DO_RTS_ERROR_FALSE FALSE
+int file_input_get_xchar(char *in_ptr, int max_chars_to_read);
+int file_input_read_xchar(char *in_ptr, int max_chars_to_read);
+int file_input_get(char **in_ptr, int max_len);
 
 #endif
diff --git a/sr_unix/ftok.c b/sr_unix/ftok.c
index 6ec3aa0..a17847d 100644
--- a/sr_unix/ftok.c
+++ b/sr_unix/ftok.c
@@ -24,10 +24,13 @@
 #include "gtm_ipc.h"
 #include <errno.h>
 #include "gtm_string.h"
+#include "cli.h"
 
 #define DEFAULT_ID	43
 #define ID_PREFIX	"-id="
 
+GBLDEF   CLI_ENTRY       *cmd_ary = NULL; /* The GTCM server does not have any command tables so initialize command array to NULL */
+
 #define PrintUsage \
 	{ \
 		FPRINTF(stderr, "\nUsage:\n"); \
diff --git a/sr_unix/generate_help.csh b/sr_unix/generate_help.csh
new file mode 100644
index 0000000..4f41e09
--- /dev/null
+++ b/sr_unix/generate_help.csh
@@ -0,0 +1,102 @@
+#################################################################
+#								#
+#	Copyright 2014 Fidelity Infromation Services, Inc	#
+#								#
+#	This source code contains the intellectual property	#
+#	of its copyright holder(s), and is made available	#
+#	under a license.  If you do not know the terms of	#
+#	the license, please stop and do not read further.	#
+#								#
+#################################################################
+
+#
+# (re)Generate GT.M and Utility Help global directories and files on demand
+#
+# Parameters:
+#   HLP file location (defaults to $gtm_pct)
+#   Error log file (used to redirect output to error file in comlist.csh)
+
+
+set hlpdir = $1
+if ("" == "${hlpdir}") then
+	if (0 == $?gtm_pct) then
+		echo "HLP file location was not supplied and \$gtm_pct is not defined"
+		exit -1
+	endif
+	set hlpdir = ${gtm_pct}
+	if (! -e ${hlpdir}) then
+		echo "HLP file location does not exist"
+		exit -2
+	endif
+endif
+
+set errout = ""
+if ("" != "${2}") set errout = ">> $2"
+
+# Need write permissions to $gtm_dist
+if (! -w ${gtm_dist}) then
+	set restorePerms = `filetest -P $gtm_dist`
+	chmod ugo+w ${gtm_dist}
+	if ($status) then
+		echo "User does not have sufficient privileges to get write access to $gtm_dist, cannot update help"
+		exit -3
+	endif
+endif
+
+set script_stat = 0
+foreach hlp (${hlpdir}/*.hlp)
+	# Extract the HLP file name and fix-up the mumps to gtm
+	set prefix=${hlp:t:r:s/mumps/gtm/}
+
+	# If the HLP files are newer than the help database create a new one, otherwise skip it
+	if ( `filetest -C ${hlp}` > `filetest -C $gtm_dist/${prefix}help.dat` ) then
+		\rm -f  ${gtm_dist}/${prefix}help.gld ${gtm_dist}/${prefix}help.dat
+	else
+		continue
+	endif
+
+	# Either help info does not exist or needs to be regenerated
+
+	# Define the global directory with the same prefix as the HLP file and
+	# use ${gtm_dist} in the file name to ensure dynamic lookup of the DAT
+	# for help information
+	setenv gtmgbldir ${gtm_dist}/${prefix}help.gld
+	${gtm_dist}/mumps -run GDE <<GDE_in_help
+Change -segment DEFAULT	-block=2048	-file=\$gtm_dist/${prefix}help.dat
+Change -region DEFAULT	-record=1020	-key=255
+GDE_in_help
+
+	if ($status) then
+		@ script_stat++
+		echo "genreatehelp-E-hlp, Error creating GLD for ${hlp}" $errout
+		continue
+	endif
+
+	${gtm_dist}/mupip create
+
+	if ($status) then
+		@ script_stat++
+		echo "genreatehelp-E-hlp, Error creating DAT for ${hlp}" $errout
+		continue
+	endif
+
+	${gtm_dist}/mumps -direct <<GTM_in_gtmhelp
+Do ^GTMHLPLD
+${hlp}
+Halt
+GTM_in_gtmhelp
+
+	if ($status) then
+		@ script_stat++
+		echo "genreatehelp-E-hlp, Error while processing ${hlp}" $errout
+		continue
+	endif
+end
+
+# Restore read-only status
+if ($?restorePerms) then
+	chmod ${restorePerms} ${gtm_dist}
+endif
+
+exit ${script_stat}
+
diff --git a/sr_unix/get_src_line.c b/sr_unix/get_src_line.c
index a432a23..c35cafd 100644
--- a/sr_unix/get_src_line.c
+++ b/sr_unix/get_src_line.c
@@ -35,9 +35,12 @@
 # include "gdsbt.h"
 # include "gdsfhead.h"
 # include "gv_trigger.h"
+# include "gtm_trigger.h"
 # include "cdb_sc.h"
 # include "t_retry.h"
 # include "trigger_source_read_andor_verify.h"
+# include "gtm_trigger_trc.h"
+# include "zr_unlink_rtn.h"
 #endif
 #include "stack_frame.h"
 #include "rtn_src_chksum.h"
@@ -59,14 +62,14 @@ LITDEF mval		literal_null;
 error_def(ERR_TXTSRCFMT);
 error_def(ERR_SYSCALL);
 
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig)
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec)
 {
 	int			srcrecs, *lt_ptr, size, line_indx, srcfilnamlen;
 	boolean_t		found, added, eof_seen, srcstat;
 	mstr			src;
 	rhdtyp			*rtn_vector;
 	zro_ent			*srcdir;
-	mstr			*base, *current, *top;
+	mstr			*base, *current, *top, tmprtnname;
 	char			buff[MAX_SRCLINE], *cptr, *srcfile_name;
 	char			srcnamebuf[SIZEOF(mident_fixed) + STR_LIT_LEN(DOTM)];
 	routine_source		*src_tbl;
@@ -95,6 +98,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 	 * Determine which source we need.
 	 */
 	GTMTRIG_ONLY(IS_TRIGGER_RTN(&routine->str, is_trigger));
+	DBGIFTRIGR((stderr, "get_src_line: entered $tlevel=%d and $t_tries=%d\n", dollar_tlevel, t_tries));
 	if (WANT_CURRENT_RTN(routine))
 	{	/* we want $TEXT for the routine currently executing. */
 		rtn_vector = CURRENT_RHEAD_ADR(frame_pointer->rvector);
@@ -103,21 +107,30 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 	if (is_trigger)
 	{	/* Need source on a trigger. Get trigger source loaded and/or verified which may involve
 		 * creating a TP fence and dealing with TP restarts.
-		 * ZPRINT wants a consistent view of triggers across multiple calls so it bypasses verification
-		 * after the first call. In this case, the trigger had better be found since the first call found it.
 		 */
-		if (verifytrig)
+		/* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+		 * region-name specification (the string component is unmodified). Pass in a copy of the mstr struct to
+		 * avoid modification to routine->str as it affects the caller which relies on this variable being
+		 * untouched.
+		 */
+		tmprtnname = routine->str;
+		DEBUG_ONLY(rtn_vector = NULL;)
+		DBGTRIGR((stderr, "get_src_line: fetch source for %s\n", tmprtnname.addr));
+		rc = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_SRC_LOAD, &rtn_vector);
+		if (0 != rc)
 		{
-			rc = trigger_source_read_andor_verify(&routine->str, TRIGGER_SRC_LOAD);
-			if (0 != rc)
-				return SRCNOTAVAIL;
+			if (NULL != rtn_vec)
+				*rtn_vec = NULL;
+			return SRCNOTAVAIL;
 		}
-		rtn_vector = find_rtn_hdr(&routine->str);	/* Trigger routine should be loaded now */
 		if (NULL == rtn_vector)
 		{
-			assert(verifytrig);			/* Noverify trig should always be found */
-			return SRCNOTAVAIL;			/* Could happen if trigger name got modified or uniqueified */
+			if (NULL != rtn_vec)
+				*rtn_vec = NULL;
+			return OBJMODMISS;
 		}
+		DBGTRIGR((stderr, "get_src_line: source found @0x%lx(%d)\n", rtn_vector->trigr_handle,
+					((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len));
 	} else
 #	endif
 	{
@@ -126,13 +139,20 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 			op_zlink(routine, NULL);
 			rtn_vector = find_rtn_hdr(&routine->str);
 			if (NULL == rtn_vector)
+			{
+				if (NULL != rtn_vec)
+					*rtn_vec = NULL;
 				return OBJMODMISS;
+			}
 		}
-		USHBIN_ONLY(rtn_vector = op_rhd_ext(routine, (mval *)&literal_null, rtn_vector, NULL));
+		ARLINK_ONLY(rtn_vector = op_rhd_ext(routine, (mval *)&literal_null, rtn_vector, NULL));
 	}
+	if (NULL != rtn_vec)
+		*rtn_vec = rtn_vector;
 	if (!rtn_vector->src_full_name.len)
 		return SRCNOTAVAIL;
 	src_tbl = rtn_vector->source_code;
+	DBGIFTRIGR((stderr, "get_src_line: routine has source_code 0x%lx (%d)\n", src_tbl, (src_tbl)? src_tbl->srcrecs : 0));
 	if (NULL == src_tbl)
 	{
 #		ifdef GTM_TRIGGER
@@ -142,6 +162,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 			srcsize = ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len;
 			assert(0 < srcsize);
 			assert(NULL != srcstart);
+			DBGTRIGR((stderr, "get_src_line: source is %d bytes\n%s\n", srcsize, srcstart));
 			/* Calculate source checksum */
 			if (NULL == memchr(srcstart, '\n', srcsize))
 			{	/* In this case, gtm_trigger_complink() would have written an extra newline character to the
@@ -186,12 +207,13 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 				srcstart = srcptr;
 			}
 			if (!rtn_src_chksum_match(get_ctx_checksum(&checksum_ctx), get_rtnhdr_checksum(rtn_vector)))
-			{	/* Should never happen with a trigger unless it ran into some restartable concurrency
-				 * issues. Assert we can restart and do it.
+			{	/* Should never happen inside TP with a trigger unless it ran into some restartable
+				 * concurrency issues. Assert we can restart and do it.
 				 */
-				assertpro(0 < dollar_tlevel);
-				assert(CDB_STAGNATE > t_tries);
-				t_retry(cdb_sc_triggermod);
+				DBGTRIGR((stderr, "get_src_line: rtn_src_chksum_match failed dumping trigger structure\n"));
+				assert(NULL != rtn_vector->trigr_handle);
+				if (0 < dollar_tlevel)
+					t_retry(cdb_sc_triggermod);
 			}
 		} else
 #		endif
@@ -202,6 +224,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 		rtn_vector->source_code = src_tbl;
 	} else
 		srcstat |= src_tbl->srcstat;
+	DBGIFTRIGR((stderr, " get_src_line: $tlevel %d\t", dollar_tlevel));
 	lt_ptr = (int *)find_line_addr(rtn_vector, &label->str, 0, NULL);
 	if (!lt_ptr)
 		srcstat |= LABELNOTFOUND;
@@ -209,6 +232,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 	{
 		line_indx = (int)(lt_ptr - (int *)LNRTAB_ADR(rtn_vector));
 		line_indx += offset;
+		DBGIFTRIGR((stderr, "get_src_line: line_indx %d\n", line_indx));
 		if (line_indx == 0)
 			srcstat |= ZEROLINE;
 		else if (line_indx < 0)
@@ -221,6 +245,7 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 			/* DBGFPF((stderr, "get_src_line: returning string %.*s\n", (*srcret)->len, (*srcret)->addr)); */
 		}
 	}
+	DBGIFTRIGR((stderr, "get_src_line: exiting with srcstat %d\n", srcstat));
 	return srcstat;
 }
 
@@ -308,7 +333,7 @@ STATICFNDEF boolean_t fill_src_tbl_via_mfile(routine_source **src_tbl_result, rh
 	srcstat = 0;
 	srcfile_name = malloc(rtn_vector->src_full_name.len + 1);
 	memcpy(srcfile_name, rtn_vector->src_full_name.addr, rtn_vector->src_full_name.len);
-	*(srcfile_name + rtn_vector->src_full_name.len) = 0;	/* ensure string is null terminated */
+	*(srcfile_name + rtn_vector->src_full_name.len) = '\0';	/* Ensure string is null terminated */
 	/* At this point, it is not clear if Fopen will handle zos tagging correctly in all cases.
 	 * especially when tagged with other than ISO8859-1 or IBM-1047. When we resurrect the zOS
 	 * platform, we need to test this out.
@@ -325,7 +350,7 @@ STATICFNDEF boolean_t fill_src_tbl_via_mfile(routine_source **src_tbl_result, rh
 		MEMCPY_LIT(&srcnamebuf[srcfilnamlen], DOTM);
 		src.addr = srcnamebuf;
 		src.len = INTCAST(srcfilnamlen + STR_LIT_LEN(DOTM));
-		zro_search (0, 0, &src, &srcdir, TRUE);
+		zro_search(NULL, NULL, &src, &srcdir, TRUE);
 		if (srcdir)
 		{
 			srcfile_name = malloc(src.len + srcdir->str.len + 2);
diff --git a/sr_unix/geteditor.c b/sr_unix/geteditor.c
index b477689..07ba1e6 100644
--- a/sr_unix/geteditor.c
+++ b/sr_unix/geteditor.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -13,10 +13,11 @@
 
 #include "gtm_string.h"
 #include "gtm_stdlib.h"
-#include "gtm_stat.h"
+#include "gtm_unistd.h"
 
 #include "eintr_wrappers.h"
 #include "geteditor.h"
+#include "wbox_test_init.h"
 
 GBLDEF mstr editor;
 
@@ -24,8 +25,7 @@ void geteditor(void)
 {
 	char		*edt, **pedt;
 	short		len;
-	int		stat_res, iter;
-	struct stat	edt_stat;
+	int		iter;
 	char		*editor_list[] =
 			{
 				"/usr/bin/vi",
@@ -37,12 +37,11 @@ void geteditor(void)
 	edt = GETENV("EDITOR");
 	pedt = &editor_list[0];
 	do {
-		STAT_FILE(edt, &edt_stat, stat_res);
-		if (!stat_res)
+		if (0 == ACCESS(edt, (F_OK|X_OK))) /* if the file exists and is executable we are good */
 			break;
 		edt = *pedt++;
 	} while (edt);
-
+	WBTEST_ASSIGN_ONLY(WBTEST_BADEDITOR_GETEDITOR, edt, 0);
 	if (edt)
 	{
 		len = strlen(edt) + 1;	/* for zero */
diff --git a/sr_unix/go_load.c b/sr_unix/go_load.c
index 64fb2f6..3883c65 100644
--- a/sr_unix/go_load.c
+++ b/sr_unix/go_load.c
@@ -39,6 +39,7 @@
 #include <rtnhdr.h>
 #include "gv_trigger.h"
 #include "mu_interactive.h"
+#include "wbox_test_init.h"
 
 GBLREF bool		mupip_error_occurred;
 GBLREF bool		mu_ctrly_occurred;
@@ -59,7 +60,7 @@ error_def(ERR_RECLOAD);
 #define GO_PUT_SUB		0
 #define GO_PUT_DATA		1
 #define GO_SET_EXTRACT		2
-#define DEFAULT_MAX_REC_SIZE 3096
+#define DEFAULT_MAX_REC_SIZE	3096
 #define ISSUE_TRIGDATAIGNORE_IF_NEEDED(KEYLENGTH, PTR, HASHT_GBL)								\
 {																\
 	/* The ordering of the && below is important as the caller uses HASHT_GBL to be set to TRUE if the global pointed to 	\
@@ -74,11 +75,12 @@ error_def(ERR_RECLOAD);
 
 void go_call_db(int routine, char *parm1, int parm2, int val_off1, int val_len1);
 
-void go_load(uint4 begin, uint4 end)
+void go_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len, char *line2_ptr, int line2_len)
 {
 	char		*ptr;
 	int		len, fmt, keylength, keystate;
-	uint4	        iter, max_data_len, max_subsc_len, key_count, max_rec_size;
+	uint4	        max_data_len, max_subsc_len, max_rec_size;
+	gtm_uint64_t	iter, tmp_rec_count, key_count;
 	mstr            src, des;
 	unsigned char   *rec_buff, ch;
 	boolean_t	utf8_extract, format_error = FALSE, hasht_ignored = FALSE, hasht_gbl = FALSE;
@@ -88,17 +90,10 @@ void go_load(uint4 begin, uint4 end)
 
 	gvinit();
 
-	max_rec_size = DEFAULT_MAX_REC_SIZE;
-	rec_buff = (unsigned char *)malloc(max_rec_size);
-
 	fmt = MU_FMT_ZWR;	/* by default, the extract format is ZWR (not GO) */
-	len = file_input_get(&ptr);
-	if (mupip_error_occurred)
-	{
-		free(rec_buff);
-		return;
-	}
-	if (len >= 0)
+	len = line1_len;
+	ptr = line1_ptr;
+	if (0 <= len)
 	{
 		util_out_print("!AD", TRUE, len, ptr);
 		utf8_extract = ((len >= STR_LIT_LEN(UTF8_NAME)) &&
@@ -110,17 +105,12 @@ void go_load(uint4 begin, uint4 end)
 			else
 				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
 			mupip_error_occurred = TRUE;
-			free(rec_buff);
 			return;
 		}
 	} else
 		mupip_exit(ERR_LOADFILERR);
-	len = file_input_get(&ptr);
-	if (mupip_error_occurred)
-	{
-		free(rec_buff);
-		return;
-	}
+	len = line2_len;
+	ptr = line2_ptr;
 	if (len >= 0)
 	{
 		util_out_print("!AD", TRUE, len, ptr);
@@ -131,16 +121,12 @@ void go_load(uint4 begin, uint4 end)
 		begin = 3;
 	for (iter = 3; iter < begin; iter++)
 	{
-		len = file_input_get(&ptr);
+		len = file_input_get(&ptr, 0);
 		if (len < 0)	/* The IO device has signalled an end of file */
 		{
 			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
 			mupip_error_occurred = TRUE;
-		}
-		if (mupip_error_occurred)
-		{
-			util_out_print("Error reading record number: !UL\n", TRUE, iter);
-			free(rec_buff);
+			util_out_print("Error reading record number: !@UQ\n", TRUE, &iter);
 			return;
 		}
 	}
@@ -149,6 +135,9 @@ void go_load(uint4 begin, uint4 end)
 	max_data_len = 0;
 	max_subsc_len = 0;
 	key_count = 0;
+	GTM_WHITE_BOX_TEST(WBTEST_FAKE_BIG_KEY_COUNT, key_count, 4294967196U); /* (2**32)-100=4294967196 */
+	max_rec_size = DEFAULT_MAX_REC_SIZE;
+	rec_buff = (unsigned char *)malloc(max_rec_size);
 	for (iter = begin - 1; ; )
 	{
 		if (++iter > end)
@@ -159,14 +148,15 @@ void go_load(uint4 begin, uint4 end)
 			break;
 		if (mu_ctrlc_occurred)
 		{
-			util_out_print("!AD:!_  Key cnt: !UL  max subsc len: !UL  max data len: !UL", TRUE,
-				       LEN_AND_LIT("LOAD TOTAL"), key_count, max_subsc_len, max_data_len);
-			util_out_print("Last LOAD record number: !UL", TRUE, key_count ? iter : 0);
+			util_out_print("!AD:!_  Key cnt: !@UQ  max subsc len: !UL  max data len: !UL", TRUE,
+				       LEN_AND_LIT("LOAD TOTAL"), &key_count, max_subsc_len, max_data_len);
+			tmp_rec_count = key_count ? iter : 0;
+			util_out_print("Last LOAD record number: !@UQ", TRUE, &tmp_rec_count);
 			mu_gvis();
 			util_out_print(0, TRUE);
 			mu_ctrlc_occurred = FALSE;
 		}
-		if (0 > (len = file_input_get(&ptr)))
+		if (0 > (len = file_input_get(&ptr, 0)))
 			break;
 		if (mupip_error_occurred)
 		{
@@ -205,7 +195,7 @@ void go_load(uint4 begin, uint4 end)
 			if (mupip_error_occurred)
 			{
 				mu_gvis();
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
 				gv_target = NULL;
 				gv_currkey->base[0] = '\0';
 				ONERROR_PROCESS;
@@ -225,7 +215,8 @@ void go_load(uint4 begin, uint4 end)
 			des.addr = (char *)rec_buff;
 			if (FALSE == zwr2format(&src, &des))
 			{
-				util_out_print("Format error in record number !8UL: !/!AD", TRUE, iter, src.len, src.addr);
+				util_out_print("Format error in record number: !@UQ!/With content:!/!AD",
+					TRUE, &iter, src.len, src.addr);
 				format_error = TRUE;
 				continue;
 			}
@@ -236,7 +227,7 @@ void go_load(uint4 begin, uint4 end)
 			if (mupip_error_occurred)
 			{
 				mu_gvis();
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
 				ONERROR_PROCESS;
 			}
 			key_count++;
@@ -245,7 +236,7 @@ void go_load(uint4 begin, uint4 end)
 			ISSUE_TRIGDATAIGNORE_IF_NEEDED(len, ptr, hasht_gbl);
 			if (hasht_gbl)
 			{
-				if (0 > (len = file_input_get(&ptr)))
+				if (0 > (len = file_input_get(&ptr, 0)))
 					break;
 				iter++;
 				hasht_gbl = FALSE;
@@ -255,7 +246,7 @@ void go_load(uint4 begin, uint4 end)
 			if (mupip_error_occurred)
 			{
 				mu_gvis();
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
 				gv_target = NULL;
 				gv_currkey->base[0] = '\0';
 				ONERROR_PROCESS;
@@ -267,12 +258,12 @@ void go_load(uint4 begin, uint4 end)
 				iter--;	/* Decrement as didn't load key */
 				break;
 			}
-			if ((len = file_input_get(&ptr)) < 0)
+			if (0 > (len = file_input_get(&ptr, 0)))
 			        break;
 			if (mupip_error_occurred)
 			{
 				mu_gvis();
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
 				break;
 			}
 			stringpool.free = stringpool.base;
@@ -282,7 +273,7 @@ void go_load(uint4 begin, uint4 end)
 			if (mupip_error_occurred)
 			{
 				mu_gvis();
-				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, iter);
+				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECLOAD, 1, &iter);
 				ONERROR_PROCESS;
 			}
 			key_count++;
@@ -295,9 +286,10 @@ void go_load(uint4 begin, uint4 end)
 		gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_LOADCTRLY);
 		mupip_exit(ERR_MUNOFINISH);
 	}
-	util_out_print("LOAD TOTAL!_!_Key Cnt: !UL  Max Subsc Len: !UL  Max Data Len: !UL",TRUE,key_count,max_subsc_len,
+	util_out_print("LOAD TOTAL!_!_Key Cnt: !@UQ  Max Subsc Len: !UL  Max Data Len: !UL",TRUE,&key_count,max_subsc_len,
 			max_data_len);
-	util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (iter - 1) : 0);
+	tmp_rec_count = key_count ? (iter - 1) : 0;
+	util_out_print("Last LOAD record number: !@UQ\n", TRUE, &tmp_rec_count);
 	if (format_error)
 		mupip_exit(ERR_LOADFILERR);
 }
diff --git a/sr_unix/grab_latch.c b/sr_unix/grab_latch.c
new file mode 100644
index 0000000..1f11cbe
--- /dev/null
+++ b/sr_unix/grab_latch.c
@@ -0,0 +1,84 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 DEBUG
+#include "gtm_unistd.h"	/* for "getpid" */
+#endif
+
+#include "interlock.h"
+#include "performcaslatchcheck.h"
+#include "rel_quant.h"
+#include "sleep_cnt.h"
+#include "wcs_sleep.h"
+
+GBLREF	int		num_additional_processors;
+GBLREF	uint4		process_id;
+GBLREF	volatile int4	fast_lock_count;		/* Stop interrupts while we have our parts exposed */
+
+/* Grab a latch. If cannot get it in "max_retries" attempts, return FALSE, else TRUE.
+ * Check for a max of 4 times whether holder pid is dead and if so salvage the lock.
+ * Dont do it frequently as it involves is_proc_alive check which is a system call.
+ */
+boolean_t grab_latch(sm_global_latch_ptr_t latch, int max_timeout_in_secs)
+{
+	int	max_retries, retries, spins, maxspins, quarter_retries, next_cascheck, cursleep;
+
+	assert(process_id == getpid());	/* make sure "process_id" global variable is reliable (used below in an assert) */
+	if (process_id == latch->u.parts.latch_pid)
+	{	/* already have lock */
+		assert(FALSE);	/* dont expect caller to call us if we hold the lock already. in pro be safe and return */
+		return TRUE;
+	}
+	++fast_lock_count;	/* Disable interrupts (i.e. wcs_stale) for duration to avoid potential deadlocks */
+	/* Compute "max_retries" so total sleep time is "max_timeout_in_secs" seconds */
+	quarter_retries = max_timeout_in_secs * MILLISECS_IN_SEC;
+	DEBUG_ONLY(
+		if (!quarter_retries)
+			quarter_retries = 1;	/* dbg call to do grab_latch_immediate, reset to just 1 iteration */
+	)
+	max_retries = quarter_retries * 4; /* 1 loop in 4 is sleep of 1 msec */
+	maxspins = num_additional_processors ? MAX_LOCK_SPINS(max_retries, num_additional_processors) : 1;
+	next_cascheck = max_retries - quarter_retries;
+	cursleep = MINSLPTIME;
+	for (retries = max_retries - 1; 0 < retries; retries--)	/* - 1 so do rel_quant 3 times first */
+	{
+		for (spins = maxspins; 0 < spins; spins--)
+		{	/* We better not hold it if trying to get it */
+			assert(latch->u.parts.latch_pid != process_id);
+                        if (GET_SWAPLOCK(latch))
+			{	/* Note that fast_lock_count is kept incremented for the duration that we hold the lock
+				 * to prevent our dispatching an interrupt that could deadlock getting this lock
+				 */
+				--fast_lock_count;
+				assert(0 <= fast_lock_count);
+				return TRUE;
+			}
+		}
+		/* Now that we have done a lot of spin, sleep a little. Do not use rel_quant as benchmarks done seem to
+		 * suggest it is a more costly operation (system call + cpu overhead) in an environment with lots of processes.
+		 */
+		wcs_sleep(cursleep++);
+		if (MAXSLPTIME == cursleep)
+			cursleep = MINSLPTIME;	/* start all over again in sleep loop */
+		/* For a total of 3 times in this function, see if target is dead and/or wake it up */
+		if (retries == next_cascheck)
+		{
+			performCASLatchCheck(latch, TRUE);
+			next_cascheck -= quarter_retries;
+		}
+	}
+	--fast_lock_count;
+	assert(0 <= fast_lock_count);
+	assert(FALSE);
+	return FALSE;
+}
diff --git a/sr_unix/gt_timer.h b/sr_unix/gt_timer.h
index 002552a..6d520a7 100644
--- a/sr_unix/gt_timer.h
+++ b/sr_unix/gt_timer.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -83,17 +83,69 @@ typedef struct st_timer_alloc
 	struct st_timer_alloc	*next;
 } st_timer_alloc;
 
-#define MAX_TIMER_HNDLRS	10	/* Max # of safe timer handlers */
+#define MAX_SAFE_TIMER_HNDLRS	10	/* Max # of safe timer handlers */
 #define GT_WAKE
+#define CANCEL_TIMERS		cancel_unsafe_timers()
 
-/* Set each timer request to go for 10ms more than requested, since the
- * interval timer alarm will sometimes go off early on many UNIX systems.
- * 10ms is more than enough for all systems tested so far (SunOS, Solaris,
- * HP/UX, NonStop/UX)
+/* Uncomment the below #define if you want to print the status of the key timer-related variables as well as the entire timer queue
+ * when operations such as addition, cancelation, or handling of a timer occur.
+ *
+ * #define TIMER_DEBUGGING
  */
-#define SLACKTIME		10
 
-#define CANCEL_TIMERS		cancel_unsafe_timers()
+#ifdef TIMER_DEBUGGING
+#  define DUMP_TIMER_INFO(LOCATION)								\
+{												\
+	int		i;									\
+	GT_TIMER	*cur_timer;								\
+	char		*s_heartbeat_timer = "heartbeat_timer";					\
+	char		*s_wcs_clean_dbsync = "wcs_clean_dbsync";				\
+	char		*s_wcs_stale = "wcs_stale";						\
+	char		*s_hiber_wake = "hiber_wake";						\
+	char		*s_unknown = "unknown";							\
+	char		*handler;								\
+												\
+	cur_timer = (GT_TIMER *)timeroot;							\
+	FPRINTF(stderr, "------------------------------------------------------\n"		\
+		"%s\n---------------------------------\n"					\
+		"Timer Info:\n"									\
+		"  system timer active: %d\n"							\
+		"  timer in handler:    %d\n"							\
+		"  timer stack count:   %d\n"							\
+		"  heartbeat started:   %d\n",							\
+		LOCATION, timer_active, timer_in_handler, timer_stack_count, heartbeat_started);\
+	FFLUSH(stderr);										\
+	i = 0;											\
+	while (cur_timer)									\
+	{											\
+		if ((void (*)())heartbeat_timer_ptr == cur_timer->handler)			\
+			handler = s_heartbeat_timer;						\
+		else if ((void (*)())wcs_clean_dbsync_fptr == cur_timer->handler)		\
+			handler = s_wcs_clean_dbsync;						\
+		else if ((void (*)())wcs_stale_fptr == cur_timer->handler)			\
+			handler = s_wcs_stale;							\
+		else if ((void (*)())hiber_wake == cur_timer->handler)				\
+			handler = s_hiber_wake;							\
+		else										\
+			handler = s_unknown;							\
+		FPRINTF(stderr, "  - timer #%d:\n"						\
+			"      handler:    %s\n"						\
+			"      safe:       %d\n"						\
+			"      start_time: [at_sec: %ld; at_usec: %ld]\n"			\
+			"      expir_time: [at_sec: %ld; at_usec: %ld]\n",			\
+			i, handler, cur_timer->safe,						\
+			cur_timer->start_time.at_sec, cur_timer->start_time.at_usec,		\
+			cur_timer->expir_time.at_sec, cur_timer->expir_time.at_usec);		\
+		FFLUSH(stderr);									\
+		cur_timer = cur_timer->next;							\
+		i++;										\
+	}											\
+	FPRINTF(stderr, "------------------------------------------------------\n");		\
+	FFLUSH(stderr);										\
+}
+#else
+#  define DUMP_TIMER_INFO(LOCATION)
+#endif
 
 int4		abs_time_comp(ABS_TIME *atp1, ABS_TIME *atp2);
 void		add_int_to_abs_time(ABS_TIME *atps, int4 ival, ABS_TIME *atpd);
diff --git a/sr_unix/gt_timers.c b/sr_unix/gt_timers.c
index bcbedf8..44bdc3b 100644
--- a/sr_unix/gt_timers.c
+++ b/sr_unix/gt_timers.c
@@ -26,7 +26,7 @@
  *
  * Following are top-level user-callable routines of this package:
  *
- * void sys_get_cur_time(ABS_TIME *atp)
+ * void sys_get_curr_time(ABS_TIME *atp)
  * 	fetch absolute time into stucture
  *
  * void hiber_start(uint4 hiber)
@@ -77,15 +77,10 @@
 #include "util.h"
 #include "sleep.h"
 #include "error.h"
-#if defined(__osf__)
-# define HZ	CLK_TCK
-#elif defined(__MVS__)
-# define HZ	gtm_zos_HZ
-STATICDEF int	gtm_zos_HZ = 100;	/* see prealloc_gt_timers below */
-#endif
 
 #ifdef ITIMER_REAL
 # define BSD_TIMER
+# define USER_HZ 1000
 #else
 /* check def of time() including arg - see below; should be time_t
  * (from sys/types.h) and traditionally unsigned long */
@@ -131,7 +126,7 @@ STATICDEF struct itimerval	sys_timer, old_sys_timer;
 STATICDEF boolean_t		in_setitimer_error;
 #endif
 
-#define DUMMY_SIG_NUM		0	/* following can be used to see why timer_handler was called */
+#define DUMMY_SIG_NUM		0		/* following can be used to see why timer_handler was called */
 
 STATICDEF volatile GT_TIMER *timeroot = NULL;	/* chain of pending timer requests in time order */
 STATICDEF boolean_t first_timeset = TRUE;
@@ -139,14 +134,14 @@ STATICDEF struct sigaction prev_alrm_handler;	/* save previous SIGALRM handler,
 
 /* Chain of unused timer request blocks */
 STATICDEF volatile	GT_TIMER	*timefree = NULL;
-STATICDEF volatile 	int4		num_timers_free;	/* # of timers in the unused queue */
+STATICDEF volatile 	int4		num_timers_free;		/* # of timers in the unused queue */
 STATICDEF		int4		timeblk_hdrlen;
 STATICDEF volatile 	st_timer_alloc	*timer_allocs = NULL;
 
-STATICDEF int 		safe_timer_cnt, timer_pop_cnt;		/* Number of safe timers in queue/popped */
+STATICDEF int 		safe_timer_cnt, timer_pop_cnt;			/* Number of safe timers in queue/popped */
 STATICDEF TID 		*deferred_tids;
 
-STATICDEF timer_hndlr	safe_handlers[MAX_TIMER_HNDLRS + 1];	/* +1 for NULL to terminate list, or can use safe_handlers_cnt */
+STATICDEF timer_hndlr	safe_handlers[MAX_SAFE_TIMER_HNDLRS + 1];	/* +1 for NULL to terminate list */
 STATICDEF int		safe_handlers_cnt;
 
 STATICDEF boolean_t	stolen_timer = FALSE;	/* only complain once, used in check_for_timer_pops() */
@@ -259,28 +254,11 @@ void set_blocksig(void)
 
 /* Initialize group of timer blocks */
 void prealloc_gt_timers(void)
-{	/* On certain boxes SYSCONF in this function might get called earlier than
-	 * the one in set_num_additional_processors(), so unset white_box_enabled
-	 * for this SYSCONF to avoid issues
-	 */
-#	ifdef __MVS__
-#	  ifdef DEBUG
-	boolean_t white_box_enabled = gtm_white_box_test_case_enabled;
-	if (white_box_enabled)
-		gtm_white_box_test_case_enabled = FALSE;
-#	  endif
-	SYSCONF(_SC_CLK_TCK, gtm_zos_HZ);	/* get the real value */
-#	  ifdef DEBUG
-	if (white_box_enabled)
-		gtm_white_box_test_case_enabled = TRUE;
-#	  endif
-#	endif
-
-	/* Preallocate some timer blocks. This will be all the timer blocks we hope to need.
+{	/* Preallocate some timer blocks. This will be all the timer blocks we hope to need.
 	 * Allocate them with 8 bytes of possible data each.
 	 * If more timer blocks are needed, we will allocate them as needed.
 	 */
-	gt_timers_alloc();	/* Allocate timers */
+	gt_timers_alloc();
 	/* Now initialize the safe timers. Must be done dynamically to avoid the situation where this module always references all
 	 * possible safe timers thus pulling extra stuff into executables that don't need or want it.
 	 *
@@ -329,7 +307,7 @@ void hiber_start(uint4 hiber)
 	{	/* normally, if SIGALRMs are blocked, we must already be inside a timer handler, but someone can actually disable
 		 * SIGALRMs, in which case we do not want this assert to trip in pro */
 		assert(1 <= timer_stack_count);
-		NANOSLEEP(hiber);
+		SLEEP_USEC(hiber, TRUE);
 	} else
 	{
 		assertpro(1 > timer_stack_count);	/* if SIGALRMs are not blocked, we cannot be inside a timer handler */
@@ -367,7 +345,7 @@ void hiber_start_wait_any(uint4 hiber)
 	/* Even though theoretically it is possible for any signal other than SIGALRM to discontinue the wait in sigsuspend,
 	 * the intended use of this function targets only timer-scheduled events. For that reason, assert that SIGALRMs are
 	 * not blocked prior to scheduling a timer, whose delivery we will be waiting upon, as otherwise we might end up
-	 * waiting indefinitely. Note, however, that the use of NANOSLEEP in hiber_start, explained in the accompanying
+	 * waiting indefinitely. Note, however, that the use of SLEEP_USEC in hiber_start, explained in the accompanying
 	 * comment, should not be required in hiber_start_wait_any, as we presently do not invoke this function in interrupt-
 	 * induced code, and so we should not end up here with SIGALARMs blocked.
 	 */
@@ -378,10 +356,10 @@ void hiber_start_wait_any(uint4 hiber)
 	sigprocmask(SIG_SETMASK, &savemask, NULL);	/* reset signal handlers */
 }
 
-/* Wrapper function for start_timer() that is exposed for outside use. The function ensure that time_to_expir is positive. If
- * negative value or 0 is passed, set time_to_expir to SLACKTIME and invoke start_timer(). The reason we have not merged this
- * functionality with start_timer() is because there is no easy way to determine whether the function is invoked from inside
- * GT.M or by an external routine.
+/* Wrapper function for start_timer() that is exposed for outside use. The function ensures that time_to_expir is positive. If
+ * negative value or 0 is passed, set time_to_expir to 0 and invoke start_timer(). The reason we have not merged this functionality
+ * with start_timer() is because there is no easy way to determine whether the function is invoked from inside GT.M or by an
+ * external routine.
  * Arguments:	tid 		- timer id
  *		time_to_expir	- time to expiration in msecs
  *		handler		- pointer to handler routine
@@ -395,7 +373,7 @@ void gtm_start_timer(TID tid,
 		 void *hdata)
 {
 	if (0 >= time_to_expir)
-		time_to_expir = SLACKTIME;
+		time_to_expir = 0;
 	start_timer(tid, time_to_expir, handler, hdata_len, hdata);
 }
 
@@ -416,7 +394,8 @@ void start_timer(TID tid,
 	boolean_t	safe_timer = FALSE, safe_to_add = FALSE;
 	int		i;
 
-	assertpro(0 < time_to_expir);			/* Callers should verify non-zero time */
+	assertpro(0 <= time_to_expir);			/* Callers should verify non-zero time */
+	DUMP_TIMER_INFO("At the start of start_timer()");
 	if (NULL == handler)
 	{
 		safe_to_add = TRUE;
@@ -451,6 +430,7 @@ void start_timer(TID tid,
 	sigprocmask(SIG_BLOCK, &blockalrm, &savemask);	/* block SIGALRM signal */
 	start_timer_int(tid, time_to_expir, handler, hdata_len, hdata, safe_timer);
 	sigprocmask(SIG_SETMASK, &savemask, NULL);	/* reset signal handlers */
+	DUMP_TIMER_INFO("At the end of start_timer()");
 }
 
 /* Internal version of start_timer that does not protect itself, assuming this has already been done.
@@ -460,7 +440,7 @@ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(),
 {
 	ABS_TIME at;
 
- 	assert(0 != time_to_expir);
+ 	assert(0 <= time_to_expir);
 	sys_get_curr_time(&at);
 	if (first_timeset)
 	{
@@ -477,7 +457,9 @@ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(),
 	/* Check if # of free timer slots is less than minimum threshold. If so, allocate more of those while it is safe to do so */
 	if ((GT_TIMER_EXPAND_TRIGGER > num_timers_free) && (1 > timer_stack_count))
 		gt_timers_alloc();
+	DUMP_TIMER_INFO("Before invoking add_timer()");
 	add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata, safe_timer);	/* Put new timer in the queue. */
+	DUMP_TIMER_INFO("After invoking add_timer()");
 	if ((timeroot->tid == tid) || !timer_active)
 		start_first_timer(&at);
 }
@@ -492,6 +474,7 @@ void cancel_timer(TID tid)
 	boolean_t	first_timer;
 
 	sigprocmask(SIG_BLOCK, &blockalrm, &savemask);	/* block SIGALRM signal */
+	DUMP_TIMER_INFO("At the start of cancel_timer()");
 	sys_get_curr_time(&at);
 	first_timer = (timeroot && (timeroot->tid == tid));
 	remove_timer(tid);		/* remove it from the chain */
@@ -503,6 +486,7 @@ void cancel_timer(TID tid)
 			sys_canc_timer();
 	}
 	sigprocmask(SIG_SETMASK, &savemask, NULL);
+	DUMP_TIMER_INFO("At the end of cancel_timer()");
 }
 
 /* Clear the timers' state for the forked-off process. */
@@ -539,15 +523,8 @@ STATICFNDEF void sys_settimer(TID tid, ABS_TIME *time_to_expir, void (*handler)(
 #	ifdef BSD_TIMER
 	if (in_setitimer_error)
 		return;
-	if ((time_to_expir->at_sec == 0) && (time_to_expir->at_usec < (1000000 / HZ)))
-	{
-		sys_timer.it_value.tv_sec = 0;
-		sys_timer.it_value.tv_usec = 1000000 / HZ;
-	} else
-	{
-		sys_timer.it_value.tv_sec = time_to_expir->at_sec;
-		sys_timer.it_value.tv_usec = (gtm_tv_usec_t)time_to_expir->at_usec;
-	}
+	sys_timer.it_value.tv_sec = time_to_expir->at_sec;
+	sys_timer.it_value.tv_usec = (gtm_tv_usec_t)time_to_expir->at_usec;
 	sys_timer.it_interval.tv_sec = sys_timer.it_interval.tv_usec = 0;
 	assert(1000000 > sys_timer.it_value.tv_usec);
 	if ((-1 == setitimer(ITIMER_REAL, &sys_timer, &old_sys_timer)) || WBTEST_ENABLED(WBTEST_SETITIMER_ERROR))
@@ -568,52 +545,53 @@ STATICFNDEF void sys_settimer(TID tid, ABS_TIME *time_to_expir, void (*handler)(
  */
 STATICFNDEF void start_first_timer(ABS_TIME *curr_time)
 {
-	ABS_TIME eltime, interval;
+	ABS_TIME eltime;
 	GT_TIMER *tpop;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	DUMP_TIMER_INFO("At the start of start_first_timer()");
 	if ((1 < timer_stack_count) || (TRUE == timer_in_handler))
 	{
 		deferred_timers_check_needed = FALSE;
 		return;
 	}
 	if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && !process_exiting)
-	{
-		while (timeroot)			/* check if some timer expired while this function was getting invoked */
+	{	/* Check if some timer expired while this function was getting invoked. */
+		while (timeroot)
 		{
 			eltime = sub_abs_time((ABS_TIME *)&timeroot->expir_time, curr_time);
-			if ((0 <= eltime.at_sec) || (0 < timer_stack_count))		/* nothing has expired yet */
+			/* If nothing has expired yet, break. */
+			if ((0 < eltime.at_sec) || ((0 == eltime.at_sec) && (0 < eltime.at_usec)) || (0 < timer_stack_count))
 				break;
-			timer_handler(DUMMY_SIG_NUM); 	/* otherwise, drive the handler */
+			/* Otherwise, drive the handler. */
+			timer_handler(DUMMY_SIG_NUM);
 		}
-		if (timeroot)				/* we still have a timer to set? */
+		/* Do we still have a timer to set? */
+		if (timeroot)
 		{
-			add_int_to_abs_time(&eltime, SLACKTIME, &interval);
 			deferred_timers_check_needed = FALSE;
-			sys_settimer(timeroot->tid, &interval, timeroot->handler);	/* set system timer */
+			sys_settimer(timeroot->tid, &eltime, timeroot->handler);
 		}
-	} else if (0 < safe_timer_cnt)			/* there are some safe timers */
-	{
-		tpop = (GT_TIMER *)timeroot;		/* regular timers are not allowed here, so only handle safe timers */
+	} else if (0 < safe_timer_cnt)
+	{	/* There are some safe timers on the queue. */
+		tpop = (GT_TIMER *)timeroot;
 		while (tpop)
 		{
 			eltime = sub_abs_time((ABS_TIME *)&tpop->expir_time, curr_time);
 			if (tpop->safe)
-			{
-				if (0 > eltime.at_sec)	/* at least one safe timer has expired */
-					timer_handler(DUMMY_SIG_NUM);			/* so, drive what we can */
+			{	/* Regular timers cannot be processed here, so only handle safe timers, and only if expired. */
+				if ((0 > eltime.at_sec) || ((0 == eltime.at_sec) && (0 == eltime.at_usec)))
+					timer_handler(DUMMY_SIG_NUM);
 				else
-				{
-					add_int_to_abs_time(&eltime, SLACKTIME, &interval);
-					sys_settimer(tpop->tid, &interval, tpop->handler);
-				}
+					sys_settimer(tpop->tid, &eltime, tpop->handler);
 				break;
 			} else if (0 > eltime.at_sec)
 				deferred_timers_check_needed = TRUE;
 			tpop = tpop->next;
 		}
 	}
+	DUMP_TIMER_INFO("At the end of start_first_timer()");
 }
 
 /* Timer handler. This is the main handler routine that is being called by the kernel upon receipt
@@ -636,6 +614,7 @@ STATICFNDEF void timer_handler(int why)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	DUMP_TIMER_INFO("At the start of timer_handler()");
 	if (SIGALRM == why)
 	{	/* If why is 0, we know that timer_handler() was called directly, so no need
 		 * to check if the signal needs to be forwarded to appropriate thread.
@@ -763,6 +742,7 @@ STATICFNDEF void timer_handler(int why)
 	SET_ERROR_CONDITION(save_error_condition);	/* restore error_condition & severity */
 	errno = save_errno;			/* restore mainline errno by similar reasoning as mainline error_condition */
 	timer_stack_count--;
+	DUMP_TIMER_INFO("At the end of timer_handler()");
 }
 
 /* Find a timer given by tid in the timer chain.
diff --git a/sr_unix/gtm_env_init_sp.c b/sr_unix/gtm_env_init_sp.c
index 4c236ee..0286556 100644
--- a/sr_unix/gtm_env_init_sp.c
+++ b/sr_unix/gtm_env_init_sp.c
@@ -66,6 +66,8 @@
 # define GTM_USESECSHR				"$gtm_usesecshr"
 /* GTM_TEST_FAKE_ENOSPC is used only in debug code so it does not have to go in gtm_logicals.h */
 # define GTM_TEST_FAKE_ENOSPC			"$gtm_test_fake_enospc"
+/* GTM_TEST_AUTORELINK_ALWAYS is used only in debug code so it does not have to go in gtm_logicals.h */
+# define GTM_TEST_AUTORELINK_ALWAYS		"$gtm_test_autorelink_always"
 #endif
 #define DEFAULT_MUPIP_TRIGGER_ETRAP 		"IF $ZJOBEXAM()"
 
@@ -77,7 +79,6 @@
 #endif
 #define MAX_TRANS_NAME_LEN			GTM_PATH_MAX
 
-GBLREF	int4			gtm_shmflags;			/* Shared memory flags for shmat() */
 GBLREF	uint4			gtm_principal_editing_defaults;	/* ext_cap flags if tt */
 GBLREF	boolean_t		is_gtm_chset_utf8;
 GBLREF	boolean_t		utf8_patnumeric;
@@ -128,6 +129,7 @@ void	gtm_env_init_sp(void)
 	char		buf[MAX_TRANS_NAME_LEN], *token, cwd[GTM_PATH_MAX];
 	char		*cwdptr, *trigger_etrap, *c, *end;
 	struct stat	outbuf;
+	int		gtm_autorelink_shm_min;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -156,9 +158,6 @@ void	gtm_env_init_sp(void)
 		} /* else gtm_core_file/gtm_core_putenv remain null and we likely cannot generate proper core files */
 	}
 #	endif
-	val.addr = GTM_SHMFLAGS;
-	val.len = SIZEOF(GTM_SHMFLAGS) - 1;
-	gtm_shmflags = (int4)trans_numeric(&val, &is_defined, TRUE);	/* Flags vlaue (0 is undefined or bad) */
 	val.addr = GTM_QUIET_HALT;
 	val.len = SIZEOF(GTM_QUIET_HALT) - 1;
 	ret = logical_truth_value(&val, FALSE, &is_defined);
@@ -345,7 +344,7 @@ void	gtm_env_init_sp(void)
 	{
 		init_relink_allowed(&trans); /* set TREF(relink_allowed) */
 	}
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
 	/* Set default or supplied value for $gtm_linktmpdir */
 	val.addr = GTM_LINKTMPDIR;
 	val.len = SIZEOF(GTM_LINKTMPDIR) - 1;
@@ -360,14 +359,15 @@ void	gtm_env_init_sp(void)
 		}
 	}
 	assert(GTM_PATH_MAX > trans.len);
+	/* Remove trailing '/' from path */
+	while ((1 < trans.len) && ('/' == trans.addr[trans.len - 1]))
+		trans.len--;
 	(TREF(gtm_linktmpdir)).addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */
 	(TREF(gtm_linktmpdir)).len = trans.len;
 	/* For now, we assume that if the environment variable is defined to NULL, anticipatory freeze is NOT in effect */
 	if (0 < trans.len)
-	{
 		memcpy((TREF(gtm_linktmpdir)).addr, trans.addr, trans.len);
-		((TREF(gtm_linktmpdir)).addr)[trans.len] = '\0';
-	}
+	((TREF(gtm_linktmpdir)).addr)[trans.len] = '\0';
 	STAT_FILE((TREF(gtm_linktmpdir)).addr, &outbuf, stat_res);
 	if ((-1 == stat_res) || !S_ISDIR(outbuf.st_mode))
 	{	/* Either the directory doesn't exist or the entity is not a directory */
@@ -376,7 +376,24 @@ void	gtm_env_init_sp(void)
 		(TREF(gtm_linktmpdir)).len = SIZEOF(DEFAULT_GTM_TMP) - 1;
 		(TREF(gtm_linktmpdir)).addr = DEFAULT_GTM_TMP;
 	}
-#	endif
+	/* See if gtm_autorelink_shm is set */
+	val.addr = GTM_AUTORELINK_SHM;
+	val.len = SIZEOF(GTM_AUTORELINK_SHM) - 1;
+	gtm_autorelink_shm_min = trans_numeric(&val, &is_defined, TRUE);
+	if (!is_defined || !gtm_autorelink_shm_min)
+		TREF(relinkctl_shm_min_index) = 0;
+	else
+	{
+		gtm_autorelink_shm_min = (2 <= gtm_autorelink_shm_min) ? ceil_log2_32bit(gtm_autorelink_shm_min) : 0;
+		TREF(relinkctl_shm_min_index) = gtm_autorelink_shm_min;
+	}
+	/* See if gtm_autorelink_keeprtn is set */
+	val.addr = GTM_AUTORELINK_KEEPRTN;
+	val.len = SIZEOF(GTM_AUTORELINK_KEEPRTN) - 1;
+	TREF(gtm_autorelink_keeprtn) = logical_truth_value(&val, FALSE, &is_defined);
+	if (!is_defined)
+		TREF(gtm_autorelink_keeprtn) = FALSE;
+#	endif /* AUTORELINK_SUPPORTED */
 #	ifdef DEBUG
 	/* DEBUG-only option to bypass 'easy' methods of things and always use gtmsecshr for IPC cleanups, wakeups, file removal,
 	 * etc. Basically use gtmsecshr for anything where it is an option - helps with testing gtmsecshr for proper operation.
@@ -392,6 +409,12 @@ void	gtm_env_init_sp(void)
 	TREF(gtm_test_fake_enospc) = logical_truth_value(&val, FALSE, &is_defined);
 	if (!is_defined)
 		TREF(gtm_test_fake_enospc) = FALSE;
+	/* DEBUG-only option to enable autorelink on all directories in $zroutines (except for shlib directories) */
+	val.addr = GTM_TEST_AUTORELINK_ALWAYS;
+	val.len = SIZEOF(GTM_TEST_AUTORELINK_ALWAYS) - 1;
+	TREF(gtm_test_autorelink_always) = logical_truth_value(&val, FALSE, &is_defined);
+	if (!is_defined)
+		TREF(gtm_test_autorelink_always) = FALSE;
 #	endif
 #	ifdef GTMDBGFLAGS_ENABLED
 	val.addr = GTMDBGFLAGS;
diff --git a/sr_unix/gtm_exit_handler.c b/sr_unix/gtm_exit_handler.c
index adee853..39d1147 100644
--- a/sr_unix/gtm_exit_handler.c
+++ b/sr_unix/gtm_exit_handler.c
@@ -53,81 +53,125 @@ GBLREF	boolean_t		need_core;			/* Core file should be created */
 GBLREF	boolean_t		created_core;			/* core file was created */
 GBLREF	unsigned int		core_in_progress;
 GBLREF	boolean_t		dont_want_core;
-GBLREF	int4			process_id;
 GBLREF	boolean_t		exit_handler_active;
-GBLREF	boolean_t		pool_init;
-GBLREF	jnlpool_addrs		jnlpool;
-GBLREF	jnlpool_ctl_ptr_t	jnlpool_ctl;
 GBLREF 	boolean_t		is_tracing_on;
 
+static	enum rundown_state	attempting;
+
 #ifdef DEBUG
 GBLREF	int			process_exiting;
-GBLREF	boolean_t		ok_to_UNWIND_in_exit_handling;
 #endif
 
+/* Note: This macro uses local variables "attempting", "error_seen" and "actual_exi_condition" */
+#define	RUNDOWN_STEP(THISSTATE, NEXTSTATE, ERRCODE, STMT)			\
+{										\
+	if (THISSTATE == attempting)						\
+	{									\
+		if (!error_seen)						\
+		{								\
+			STMT;							\
+		} else								\
+		{								\
+			if (!actual_exi_condition)				\
+				actual_exi_condition = exi_condition;		\
+			if (0 != ERRCODE)					\
+			{							\
+				PRN_ERROR;					\
+				dec_err(VARLSTCNT(1) ERRCODE);			\
+			}							\
+		}								\
+		error_seen = FALSE;						\
+		attempting++;							\
+	}									\
+	assert(NEXTSTATE == (THISSTATE + 1));					\
+}
+
+#define	MPROF_RUNDOWN_MACRO			\
+{						\
+	if (is_tracing_on)			\
+		turn_tracing_off(NULL);		\
+}
+
+#define	LOCK_RUNDOWN_MACRO										\
+{													\
+	SET_PROCESS_EXITING_TRUE;									\
+	CANCEL_TIMERS;			/* Cancel all unsafe timers - No unpleasant surprises */	\
+	secshr_db_clnup(NORMAL_TERMINATION);								\
+	if (dollar_tlevel)										\
+		OP_TROLLBACK(0);									\
+	zcall_halt();											\
+	op_lkinit();											\
+	op_unlock();											\
+	op_zdeallocate(NO_M_TIMEOUT);									\
+}
+
+#define	IO_RUNDOWN_MACRO											\
+{														\
+	/* Invoke cleanup routines for all the shared libraries loaded during external call initialisation.	\
+	 * The cleanup routines are not mandatory routines, but if defined, will be invoked before		\
+	 * closing the shared library.										\
+	 */													\
+	for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package)	\
+	{													\
+		if (package_ptr->package_clnup_rtn)								\
+			package_ptr->package_clnup_rtn();							\
+		fgn_closepak(package_ptr->package_handle, INFO);						\
+	}													\
+	relinkctl_rundown(TRUE, TRUE);	/* decrement relinkctl-attach & rtnobj-reference counts */		\
+	assert(process_exiting);										\
+	if (MUMPS_CALLIN & invocation_mode)									\
+	{													\
+		flush_pio();											\
+		io_rundown(RUNDOWN_EXCEPT_STD);									\
+	} else													\
+		io_rundown(NORMAL_RUNDOWN);									\
+	GTMCRYPT_CLOSE;												\
+}
+
+error_def(ERR_GVRUNDOWN);
+error_def(ERR_LKRUNDOWN);
+error_def(ERR_MPROFRUNDOWN);
+
+enum rundown_state
+{
+	rundown_state_mprof,
+	rundown_state_lock,
+	rundown_state_db,
+	rundown_state_io,
+	rundown_state_last
+};
+
 void gtm_exit_handler(void)
 {
-        struct sigaction	act;
-	struct extcall_package_list *package_ptr;
-        DCL_THREADGBL_ACCESS;
+	struct sigaction		act;
+	struct extcall_package_list	*package_ptr;
+	boolean_t			error_seen;
+	int4				actual_exi_condition;
+	DCL_THREADGBL_ACCESS;
 
-        SETUP_THREADGBL_ACCESS;
+	SETUP_THREADGBL_ACCESS;
 	if (exit_handler_active)	/* Don't recurse if exit handler exited */
 		return;
-	if (is_tracing_on)
-		turn_tracing_off(NULL);
 	exit_handler_active = TRUE;
-	SET_PROCESS_EXITING_TRUE;
-	CANCEL_TIMERS;			/* Cancel all unsafe timers - No unpleasant surprises */
-	ESTABLISH(lastchance1);
-	secshr_db_clnup(NORMAL_TERMINATION);
-	if (dollar_tlevel)
-		OP_TROLLBACK(0);
-	zcall_halt();
-	op_lkinit();
-	op_unlock();
-	op_zdeallocate(NO_M_TIMEOUT);
-	REVERT;
-
-	ESTABLISH(lastchance2);
-	gv_rundown();
-	REVERT;
-
-	ESTABLISH(lastchance3);
-	/* Invoke cleanup routines for all the shared libraries loaded during external call initialisation.
- 	 * The cleanup routines are not mandatory routines, but if defined, will be invoked before
-	 * closing the shared library.
+	attempting = rundown_state_mprof;
+	actual_exi_condition = 0;
+	ESTABLISH_NORET(exi_ch, error_seen);
+	RUNDOWN_STEP(rundown_state_mprof, rundown_state_lock, ERR_MPROFRUNDOWN, MPROF_RUNDOWN_MACRO);
+	RUNDOWN_STEP(rundown_state_lock, rundown_state_db, ERR_LKRUNDOWN, LOCK_RUNDOWN_MACRO);
+	RUNDOWN_STEP(rundown_state_db, rundown_state_io, ERR_GVRUNDOWN, gv_rundown());
+	/* We pass 0 (not ERR_IORUNDOWN) below to avoid displaying any error if io_rundown fails. One reason we have
+	 * seen an external filter M program fail is with a "SYSTEM-E-ENO32, Broken pipe" error if the source or receiver
+	 * server (that is communicating with it through a pipe device) closes its end of the pipe and we do not want that
+	 * to be treated as an error in rundown (it is how a pipe close happens normally).
 	 */
-	for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package)
-	{
-	    if (package_ptr->package_clnup_rtn)
-		package_ptr->package_clnup_rtn();
-	    fgn_closepak(package_ptr->package_handle, INFO);
-	}
-	relinkctl_rundown(TRUE);
-	/* We know of at least one case where the below code would error out. That is if this were a replication external
-	 * filter M program halting out after the other end of the pipe has been closed by the source server. In this case,
-	 * the io_rundown call below would error out and would invoke the lastchance3 condition handler which will do an
-	 * UNWIND that will return from gtm_exit_handler right away. To avoid an assert in the UNWIND macro (that checks
-	 * we never do UNWINDs while process_exiting is set to TRUE) set a debug-only variable to TRUE. This variable is
-	 * also checked by the assert in the UNWIND macro (see <C9K06_003278_test_failures/resolution_v2.txt> for details).
-	 */
-	assert(process_exiting);
-	DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE;)
-	if (MUMPS_CALLIN & invocation_mode)
-	{
-		flush_pio();
-		io_rundown(RUNDOWN_EXCEPT_STD);
-	} else
-		io_rundown(NORMAL_RUNDOWN);
-	DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = FALSE;)
-	GTMCRYPT_CLOSE;
+	RUNDOWN_STEP(rundown_state_io, rundown_state_last, 0, IO_RUNDOWN_MACRO);
 	REVERT;
-
 	print_exit_stats();
 	if (need_core && !created_core && !dont_want_core)	/* We needed to core */
 	{
 		++core_in_progress;
 		DUMP_CORE;		/* This will not return */
 	}
+	if (actual_exi_condition && !(MUMPS_CALLIN & invocation_mode))
+		PROCDIE(actual_exi_condition);
 }
diff --git a/sr_unix/gtm_ipc.h b/sr_unix/gtm_ipc.h
index a76c82d..7e09c0f 100644
--- a/sr_unix/gtm_ipc.h
+++ b/sr_unix/gtm_ipc.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Serivces, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Serivces, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -39,4 +39,8 @@
 
 key_t gtm_ftok(const char *path, int id);
 
+#define IPC_REMOVED(ERRNO)	((EINVAL == ERRNO) || (EIDRM == ERRNO))	/* EIDRM is only on Linux */
+#define	SEM_REMOVED(ERRNO)	IPC_REMOVED(ERRNO)
+#define	SHM_REMOVED(ERRNO)	IPC_REMOVED(ERRNO)
+
 #endif
diff --git a/sr_unix/gtm_logicals.h b/sr_unix/gtm_logicals.h
index 1a01a22..812431d 100644
--- a/sr_unix/gtm_logicals.h
+++ b/sr_unix/gtm_logicals.h
@@ -16,14 +16,15 @@
 #define	GTM_DIST_LOG			"$gtm_dist"
 
 /* Database */
-#define	GTM_GBLDIR			"$gtmgbldir"
 #define	GTM_BLKUPGRADE_FLAG		"$gtm_blkupgrade_flag"
 #define	GTM_DBFILEXT_SYSLOG_DISABLE	"$gtm_dbfilext_syslog_disable"
 #define	GTM_ENV_XLATE			"$gtm_env_translate"
 #define	GTM_FULLBLOCKWRITES		"$gtm_fullblockwrites"
 #define	GTM_GDSCERT			"$gtm_gdscert"
 #define	GTM_GVDUPSETNOOP		"$gtm_gvdupsetnoop"
+#define	GTM_GBLDIR			"$gtmgbldir"
 #define	GTM_GVUNDEF_FATAL		"$gtm_gvundef_fatal"
+#define	GTM_POOLLIMIT			"$gtm_poollimit"
 #define	GTM_TP_ALLOCATION_CLUE		"$gtm_tp_allocation_clue"
 #define	GTM_TPNOTACIDTIME		"$gtm_tpnotacidtime"
 #define	GTM_TPRESTART_LOG_DELTA		"$gtm_tprestart_log_delta"
@@ -85,7 +86,6 @@
 
 /* Database */
 #define	GTM_TMP_ENV			"$gtm_tmp"
-#define	GTM_SHMFLAGS			"$gtm_shmatflags"
 #define	GTM_TRIGGER_ETRAP		"$gtm_trigger_etrap"
 #define	GTM_SNAPTMPDIR			"$gtm_snaptmpdir"
 #define	GTM_DB_STARTUP_MAX_WAIT		"$gtm_db_startup_max_wait"
@@ -113,6 +113,8 @@
 /* [Auto]Relink related */
 #define	GTM_LINK			"$gtm_link"
 #define GTM_LINKTMPDIR			"$gtm_linktmpdir"
+#define	GTM_AUTORELINK_SHM 		"$gtm_autorelink_shm"
+#define	GTM_AUTORELINK_KEEPRTN		"$gtm_autorelink_keeprtn"	/* do not let go of objects in rtnobj shm */
 
 /* Miscellaneous */
 #define GTM_ERROR_ON_JNL_FILE_LOST	"$gtm_error_on_jnl_file_lost"
diff --git a/sr_unix/gtm_permissions.c b/sr_unix/gtm_permissions.c
index e4d5ab9..9fc30a3 100644
--- a/sr_unix/gtm_permissions.c
+++ b/sr_unix/gtm_permissions.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2009, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2009, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -137,7 +137,7 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 	/* set no permissions as a default in case none of our conditions match */
 	*perm = 0;
 
-	assertpro((PERM_FILE == target_type) || (PERM_IPC == target_type));
+	assertpro((PERM_FILE & target_type) || (PERM_IPC & target_type));
 	if (0006 & stat_buff->st_mode)
 	{
 		/* file is accessible to other */
@@ -145,10 +145,10 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 			*user_id = stat_buff->st_uid;
 		if (opener_in_file_group || opener_is_root)		/* otherwise, use default gid */
 			*group_id = stat_buff->st_gid;
-		if (PERM_FILE == target_type)
+		if (PERM_FILE & target_type)
 			*perm = (!opener_in_file_group && !opener_is_root && (0020 & stat_buff->st_mode))
 					? 0666 : (stat_buff->st_mode & 0666);
-		else if (PERM_IPC == target_type)
+		else if (PERM_IPC & target_type)
 			*perm = 0666;
 	} else if (0600 & stat_buff->st_mode && !(0066 & stat_buff->st_mode))
 	{
@@ -160,9 +160,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 			*user_id = stat_buff->st_uid;
 			*group_id = stat_buff->st_gid;
 		}
-		if (PERM_FILE == target_type)
+		if (PERM_FILE & target_type)
 			*perm = 0600;			/* read write for user */
-		else if (PERM_IPC == target_type)
+		else if (PERM_IPC & target_type)
 			*perm = 0600;			/* read write for user */
 	} else if (0060 & stat_buff->st_mode && !(0606 & stat_buff->st_mode))
 	{
@@ -171,9 +171,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 			*user_id = stat_buff->st_uid;
 		*group_id = stat_buff->st_gid;			/* use file group */
 		assert(opener_in_file_group || opener_is_root);
-		if (PERM_FILE == target_type)
+		if (PERM_FILE & target_type)
 			*perm = stat_buff->st_mode & 0060;	/* use file permissions, masked for group read/write */
-		if (PERM_IPC == target_type)
+		if (PERM_IPC & target_type)
 			*perm = 0660;			/* read/write for group - all readers need write for ipc */
 	} else
 	{
@@ -183,9 +183,9 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 			if (opener_is_root)					/* otherwise, use default uid */
 				*user_id = stat_buff->st_uid;
 			*group_id = stat_buff->st_gid;		/* use file group */
-			if (PERM_FILE == target_type)
+			if (PERM_FILE & target_type)
 				*perm = stat_buff->st_mode & 0660;	/* use file permissions, masked for user/group read/write */
-			if (PERM_IPC == target_type)
+			if (PERM_IPC & target_type)
 				*perm = 0660;			/* read/write for user/group - all readers need write for ipc */
 		} else
 		{
@@ -195,16 +195,16 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 				{
 					*group_id = lib_gid;			/* use restricted group */
 					assert(gtm_member_group_id(process_uid, *group_id));
-					if (PERM_FILE == target_type)
+					if (PERM_FILE & target_type)
 						*perm = 0660;			/* user/group read/write */
-					if (PERM_IPC == target_type)
+					if (PERM_IPC & target_type)
 						*perm = 0660;	/* read/write for user/group - all readers need write for ipc */
 				} else
 				{
 					/* use default group */
-					if (PERM_FILE == target_type)
+					if (PERM_FILE & target_type)
 						*perm = 0666;			/* read/write for all */
-					else if (PERM_IPC == target_type)
+					else if (PERM_IPC & target_type)
 						*perm = 0666;	/* read/write for all - all readers need write for ipc */
 				}
 			} else if (!opener_is_file_owner && opener_in_file_group)
@@ -213,31 +213,34 @@ int gtm_permissions(struct stat *stat_buff, int *user_id, int *group_id, int *pe
 				if (owner_in_file_group)
 				{
 					*group_id = stat_buff->st_gid;		/* use file group */
-					if (PERM_FILE == target_type)
+					if (PERM_FILE & target_type)
 						*perm = stat_buff->st_mode & 0660;	/* use masked file permissions */
-					if (PERM_IPC == target_type)
+					if (PERM_IPC & target_type)
 						*perm = 0660;	/* read/write for user/group - all readers need write for ipc */
 
 				} else if (gtm_group_restricted)
 				{
 					*group_id = lib_gid;			/* use restricted group */
 					assert(gtm_member_group_id(process_uid, *group_id));
-					if (PERM_FILE == target_type)
+					if (PERM_FILE & target_type)
 						*perm = 0660;			/* user/group read/write */
-					if (PERM_IPC == target_type)
+					if (PERM_IPC & target_type)
 						*perm = 0660;	/* read/write for user/group - all readers need write for ipc */
 				} else
 				{
 					*group_id = stat_buff->st_gid;		/* use file group */
-					if (PERM_FILE == target_type)
+					if (PERM_FILE & target_type)
 						*perm = 0666;	/* read/write for all - ensure file owner read/write access */
-					else if (PERM_IPC == target_type)
+					else if (PERM_IPC & target_type)
 						*perm = 0666;	/* read/write for all - all readers need write for ipc */
 				}
 			}
 		}
 	}
 
+	if (target_type & PERM_EXEC)
+		*perm |= ((*perm & 0444) >> 2);	/* Grab the read bits, shift them to the exec bit position, and add them back in. */
+
 	/* if we never set *perm, return error value */
 	if (*perm == 0)
 	{
diff --git a/sr_unix/gtm_permissions.h b/sr_unix/gtm_permissions.h
index cc37088..91a9e70 100644
--- a/sr_unix/gtm_permissions.h
+++ b/sr_unix/gtm_permissions.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2009, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2009, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -16,8 +16,9 @@
 
 enum perm_target_types
 {
-    PERM_FILE,			/* request permissions for creating a new file */
-    PERM_IPC			/* request permissions for initializing IPCs (shm/sem) */
+    PERM_FILE = 0x01,			/* request permissions for creating a new file */
+    PERM_IPC  = 0x02,			/* request permissions for initializing IPCs (shm/sem) */
+    PERM_EXEC = 0x80			/* request execute permissions, masked with the above */
 };
 
 struct perm_diag_data
diff --git a/sr_unix/gtm_semutils.h b/sr_unix/gtm_semutils.h
index fefc96b..f64f44c 100644
--- a/sr_unix/gtm_semutils.h
+++ b/sr_unix/gtm_semutils.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2011, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2011, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -71,7 +71,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
 																 \
 		lcl_msgstr = (gtm_ftok_sem == SEMTYPE) ? "SEMWT2LONG_FTOK_SUCCEEDED: semop for the ftok semaphore succeeded"	 \
 							: "SEMWT2LONG_ACCSEM_SUCCEEDED: semop for the ftok semaphore succeeded"; \
-		send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(lcl_msgstr));							 \
+		send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(lcl_msgstr));					 \
 	}															 \
 }
 
@@ -124,7 +124,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
 			rts_error(VARLSTCNT(11) DBFILERR_PARAMS(REG), CRITSEMFAIL_PARAMS(REG),			\
 				SEMKEYINUSE_PARAMS(UDI));							\
 		} else												\
-			GTMASSERT;										\
+			assertpro(FALSE);									\
 	} else if (ERR_MAXSEMGETRETRY == RETSTAT->status2)							\
 	{													\
 		rts_error(VARLSTCNT(7) DBFILERR_PARAMS(REG), ERR_MAXSEMGETRETRY, 1, MAX_SEMGET_RETRIES);	\
@@ -140,7 +140,7 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
 		rts_error(VARLSTCNT(13) DBFILERR_PARAMS(REG),							\
 			SEMWT2LONG_PARAMS(REG, RETSTAT, GTM_SEMTYPE, tot_wait_time));				\
 	} else													\
-		GTMASSERT;											\
+		assertpro(FALSE);										\
 }
 
 /* Set the value of semaphore number 2 ( = FTOK_SEM_PER_ID - 1) as GTM_ID. This way, in case of an orphaned
@@ -184,6 +184,4 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
 	return FALSE;													\
 }
 
-#define SEM_REMOVED(ERRNO)	((EINVAL == ERRNO) || (EIDRM == ERRNO))	/* EIDRM is only on Linux */
-
 #endif /* GTM_SEMUTILS_H */
diff --git a/sr_unix/gtm_startup.c b/sr_unix/gtm_startup.c
index 0ded3c0..5d674b4 100644
--- a/sr_unix/gtm_startup.c
+++ b/sr_unix/gtm_startup.c
@@ -59,7 +59,6 @@
 #include "generic_signal_handler.h"
 #include "init_secshr_addrs.h"
 #include "zcall_package.h"
-#include "geteditor.h"
 #include "getzdir.h"
 #include "getzmode.h"
 #include "getzprocess.h"
@@ -92,6 +91,8 @@
 #include "heartbeat_timer.h"
 #include "gt_timers_add_safe_hndlrs.h"
 #include "continue_handler.h"
+#include "jobsp.h" /* For gcall.h */
+#include "gcall.h" /* For ojchildparms() */
 
 GBLDEF void			(*restart)() = &mum_tstart;
 #ifdef __MVS__
@@ -217,7 +218,6 @@ void gtm_startup(struct startup_vector *svec)
 	INVOKE_INIT_SECSHR_ADDRS;
 	getzprocess();
 	getzmode();
-	geteditor();
 	zcall_init();
 	cmd_qlf.qlf = glb_cmd_qlf.qlf;
 	cache_init();
@@ -309,7 +309,13 @@ void gtm_startup(struct startup_vector *svec)
 	assert(FALSE == curr_symval->alias_activity);
 	curr_symval->alias_activity = TRUE;
 	lvzwr_init((enum zwr_init_types)0, (mval *)NULL);
+	TREF(in_zwrite) = FALSE;
 	curr_symval->alias_activity = FALSE;
+	if ((GTM_IMAGE == image_type) && (NULL != svec->base_addr))
+		/* We are in the grandchild at this point. This call is made to greet local variables sent from the midchild. There
+		 * is no symbol table for locals before this point so we have to greet them here, after creating the symbol table.
+		 */
+		ojchildparms(NULL, NULL, NULL);
 	if ((NULL != (TREF(mprof_env_gbl_name)).str.addr))
 		turn_tracing_on(TADR(mprof_env_gbl_name), TRUE, (TREF(mprof_env_gbl_name)).str.len > 0);
 	return;
diff --git a/sr_unix/gtm_stdio.h b/sr_unix/gtm_stdio.h
index 3b63fbd..5db6e5d 100644
--- a/sr_unix/gtm_stdio.h
+++ b/sr_unix/gtm_stdio.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -22,15 +22,23 @@
 
 #include <stdio.h>
 
+#ifdef UNIX
 /* If interrupted, this function has previously caused hangs to do a subsequent gtm_putmsg() invocation from
- * generic_signal_handler(), so just defer interrupts to be safe.
+ * generic_signal_handler(), so just defer interrupts to be safe. UNIX is a GT.M-specific compiler switch, which
+ * we expect to be undefined for any non-GT.M compilation that might include this file.
  */
-#define FDOPEN(VAR, FILE_DES, MODE)		\
+#  define FDOPEN(VAR, FILE_DES, MODE)		\
 {						\
 	DEFER_INTERRUPTS(INTRPT_IN_FDOPEN);	\
 	VAR = fdopen(FILE_DES, MODE);		\
 	ENABLE_INTERRUPTS(INTRPT_IN_FDOPEN);	\
 }
+#else
+#  define FDOPEN(VAR, FILE_DES, MODE)		\
+{						\
+	VAR = fdopen(FILD_DES, MODE);		\
+}
+#endif
 
 #define FGETS(strg, n, strm, fgets_res)	(fgets_res = fgets(strg,n,strm))
 #define Fopen				fopen
diff --git a/sr_unix/gtm_tls.h b/sr_unix/gtm_tls.h
index 6a26e8e..d68e183 100644
--- a/sr_unix/gtm_tls.h
+++ b/sr_unix/gtm_tls.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -9,8 +9,8 @@
  *								*
  ****************************************************************/
 
-#ifndef _GTM_TLS_H
-#define _GTM_TLS_H
+#ifndef GTM_TLS_H
+#define GTM_TLS_H
 
 #define gtm_tls_get_error		(*gtm_tls_get_error_fptr)
 #define gtm_tls_errno			(*gtm_tls_errno_fptr)
@@ -70,7 +70,7 @@
 #define gtm_tls_session_close		intrsafe_gtm_tls_session_close
 #define gtm_tls_fini			intrsafe_gtm_tls_fini
 
-#undef _GTM_TLS_INTERFACE_H	/* Allows us to include gtm_tls_interface.h twice. */
+#undef GTM_TLS_INTERFACE_H	/* Allows us to include gtm_tls_interface.h twice. */
 #include "gtm_tls_interface.h"	/* BYPASSOK : intentional duplicate include. */
 
 GBLREF	gtm_tls_ctx_t			*tls_ctx;
diff --git a/sr_unix/gtm_tls_impl.c b/sr_unix/gtm_tls_impl.c
index 920e345..10e53c5 100644
--- a/sr_unix/gtm_tls_impl.c
+++ b/sr_unix/gtm_tls_impl.c
@@ -49,7 +49,186 @@ STATICDEF DH			*dh512, *dh1024;	/* Diffie-Hellman structures for Ephemeral Diffi
  * EXP: Export Ciphers.
  * MD5 : MD5 message digest.
  */
-#define CIPHER_LIST			"ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+#define REPL_CIPHER_LIST			"ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+
+#define OPTIONEND ':'
+#define OPTIONENDSTR ":"
+#define OPTIONNOT '!'
+#define DEFINE_SSL_OP(OP_DEF)   { #OP_DEF , OP_DEF }
+struct gtm_ssl_options
+{
+	const char	*opt_str;
+	long		opt_val;
+};
+STATICDEF struct gtm_ssl_options gtm_ssl_verify_mode_list[] =
+{
+	DEFINE_SSL_OP(SSL_VERIFY_PEER),
+	DEFINE_SSL_OP(SSL_VERIFY_NONE),
+	DEFINE_SSL_OP(SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
+	DEFINE_SSL_OP(SSL_VERIFY_CLIENT_ONCE),
+	{NULL, 0}
+};
+STATICDEF struct gtm_ssl_options gtm_ssl_options_list[] =
+{
+#ifdef	SSL_OP_MICROSOFT_SESS_ID_BUG
+	DEFINE_SSL_OP(SSL_OP_MICROSOFT_SESS_ID_BUG),
+#endif
+#ifdef	SSL_OP_NETSCAPE_CHALLENGE_BUG
+	DEFINE_SSL_OP(SSL_OP_NETSCAPE_CHALLENGE_BUG),
+#endif
+#ifdef	SSL_OP_LEGACY_SERVER_CONNECT
+	DEFINE_SSL_OP(SSL_OP_LEGACY_SERVER_CONNECT),
+#endif
+#ifdef	SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+	DEFINE_SSL_OP(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG),
+#endif
+#ifdef	SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+	DEFINE_SSL_OP(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG),
+#endif
+#ifdef	SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+	DEFINE_SSL_OP(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER),
+#endif
+#ifdef	SSL_OP_SAFARI_ECDHE_ECDSA_BUG
+	DEFINE_SSL_OP(SSL_OP_SAFARI_ECDHE_ECDSA_BUG),
+#endif
+#ifdef	SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+	DEFINE_SSL_OP(SSL_OP_SSLEAY_080_CLIENT_DH_BUG),
+#endif
+#ifdef	SSL_OP_TLS_D5_BUG
+	DEFINE_SSL_OP(SSL_OP_TLS_D5_BUG),
+#endif
+#ifdef	SSL_OP_TLS_BLOCK_PADDING_BUG
+	DEFINE_SSL_OP(SSL_OP_TLS_BLOCK_PADDING_BUG),
+#endif
+#ifdef	SSL_OP_MSIE_SSLV2_RSA_PADDING
+	DEFINE_SSL_OP(SSL_OP_MSIE_SSLV2_RSA_PADDING),
+#endif
+#ifdef	SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+	DEFINE_SSL_OP(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS),
+#endif
+#ifdef	SSL_OP_ALL
+	DEFINE_SSL_OP(SSL_OP_ALL),
+#endif
+#ifdef	SSL_OP_NO_QUERY_MTU
+	DEFINE_SSL_OP(SSL_OP_NO_QUERY_MTU),
+#endif
+#ifdef	SSL_OP_COOKIE_EXCHANGE
+	DEFINE_SSL_OP(SSL_OP_COOKIE_EXCHANGE),
+#endif
+#ifdef	SSL_OP_NO_TICKET
+	DEFINE_SSL_OP(SSL_OP_NO_TICKET),
+#endif
+#ifdef	SSL_OP_CISCO_ANYCONNECT
+	DEFINE_SSL_OP(SSL_OP_CISCO_ANYCONNECT),
+#endif
+#ifdef	SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+	DEFINE_SSL_OP(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION),
+#endif
+#ifdef	SSL_OP_NO_COMPRESSION
+	DEFINE_SSL_OP(SSL_OP_NO_COMPRESSION),
+#endif
+#ifdef	SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+	DEFINE_SSL_OP(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION),
+#endif
+#ifdef	SSL_OP_SINGLE_ECDH_USE
+	DEFINE_SSL_OP(SSL_OP_SINGLE_ECDH_USE),
+#endif
+#ifdef	SSL_OP_SINGLE_DH_USE
+	DEFINE_SSL_OP(SSL_OP_SINGLE_DH_USE),
+#endif
+#ifdef	SSL_OP_EPHEMERAL_RSA
+	DEFINE_SSL_OP(SSL_OP_EPHEMERAL_RSA),
+#endif
+#ifdef	SSL_OP_CIPHER_SERVER_PREFERENCE
+	DEFINE_SSL_OP(SSL_OP_CIPHER_SERVER_PREFERENCE),
+#endif
+#ifdef	SSL_OP_TLS_ROLLBACK_BUG
+	DEFINE_SSL_OP(SSL_OP_TLS_ROLLBACK_BUG),
+#endif
+#ifdef	SSL_OP_NO_SSLv2
+	DEFINE_SSL_OP(SSL_OP_NO_SSLv2),
+#endif
+#ifdef	SSL_OP_NO_SSLv3
+	DEFINE_SSL_OP(SSL_OP_NO_SSLv3),
+#endif
+#ifdef	SSL_OP_NO_TLSv1
+	DEFINE_SSL_OP(SSL_OP_NO_TLSv1),
+#endif
+#ifdef	SSL_OP_NO_TLSv1_2
+	DEFINE_SSL_OP(SSL_OP_NO_TLSv1_2),
+#endif
+#ifdef	SSL_OP_NO_TLSv1_1
+	DEFINE_SSL_OP(SSL_OP_NO_TLSv1_1),
+#endif
+#ifdef	SSL_OP_PKCS1_CHECK_1
+	DEFINE_SSL_OP(SSL_OP_PKCS1_CHECK_1),
+#endif
+#ifdef	SSL_OP_PKCS1_CHECK_2
+	DEFINE_SSL_OP(SSL_OP_PKCS1_CHECK_2),
+#endif
+#ifdef	SSL_OP_NETSCAPE_CA_DN_BUG
+	DEFINE_SSL_OP(SSL_OP_NETSCAPE_CA_DN_BUG),
+#endif
+#ifdef	SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
+	DEFINE_SSL_OP(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG),
+#endif
+#ifdef	SSL_OP_CRYPTOPRO_TLSEXT_BUG
+	DEFINE_SSL_OP(SSL_OP_CRYPTOPRO_TLSEXT_BUG),
+#endif
+	{NULL, 0}
+};
+
+STATICDEF long parse_SSL_options(struct gtm_ssl_options *opt_table, size_t opt_table_size, const char *options, long current,
+					long *clear);
+STATICDEF long parse_SSL_options(struct gtm_ssl_options *opt_table, size_t opt_table_size, const char *options, long current,
+					long *clear)
+{
+	int		negate;
+	size_t		num_options, index, optionlen;
+	long		bitmask;
+	const char	*charptr, *optionend;
+
+	if (NULL == options)
+		return 0;
+	negate = 0;
+	bitmask = current;
+	num_options = opt_table_size/SIZEOF(struct gtm_ssl_options);
+	for (charptr = options; *charptr; charptr = optionend)
+	{
+		if (OPTIONEND == *charptr)
+			if ('\0' == *++charptr)
+				break;
+		optionend = strstr((const char *)charptr, OPTIONENDSTR);
+		if (NULL == optionend)
+			optionend = charptr + strlen(charptr);
+		if (OPTIONNOT == *charptr)
+		{
+			negate = TRUE;
+			charptr++;
+		} else
+			negate = FALSE;
+		optionlen = optionend - charptr;
+		for (index = 0; num_options > index ; index++)
+		{
+			if (NULL == opt_table[index].opt_str)
+				break;
+			if (0 == strncmp(opt_table[index].opt_str, charptr, optionlen))
+			{
+				if (negate)
+				{
+					bitmask &= ~opt_table[index].opt_val;
+					if (NULL != clear)
+						*clear |= opt_table[index].opt_val;
+				} else
+					bitmask |= opt_table[index].opt_val;
+				break;
+			}
+		}
+		if (num_options <= index)
+			;	/* option not found - ignore */
+	}
+	return bitmask;
+}
 
 #ifdef DEBUG_SSL
 #define SSL_DPRINT(FP, ...)		{fprintf(FP, __VA_ARGS__); fflush(FP);}	/* BYPASSOK -- cannot use FFLUSH. */
@@ -206,6 +385,8 @@ STATICFNDEF int init_dhparams(void)
 	int		rv1, rv2;
 	const char	*dh512_fn, *dh1024_fn;
 
+	if (dh1024)
+		return 0;	/* already have */
 	rv1 = config_lookup_string(&gtm_tls_cfg, "tls.dh512", &dh512_fn);
 	rv2 = config_lookup_string(&gtm_tls_cfg, "tls.dh1024", &dh1024_fn);
 	if (!rv1 && !rv2)
@@ -229,7 +410,7 @@ STATICFNDEF int init_dhparams(void)
 
 STATICFNDEF DH *tmp_dh_callback(SSL *ssl, int is_export, int keylength)
 {
-	assert(dh512 && dh1024 && (512 <= keylength));
+	assert(dh512 && dh1024 && ((512 == keylength) || (1024 == keylength)));
 	return (512 == keylength) ? dh512 : dh1024;
 }
 
@@ -245,14 +426,15 @@ const char *gtm_tls_get_error(void)
 
 gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
 {
-	const char		*CAfile = NULL, *CApath = NULL, *crl, *CAptr;
+	const char		*CAfile = NULL, *CApath = NULL, *crl, *CAptr, *cipher_list, *options_string, *verify_mode_string;
 	char			*config_env;
-	int			rv, rv1, rv2, fips_requested, fips_enabled;
+	int			rv, rv1, rv2, fips_requested, fips_enabled, verify_mode;
 #	if (((LIBCONFIG_VER_MAJOR == 1) && (LIBCONFIG_VER_MINOR >= 4)) || (LIBCONFIG_VER_MAJOR > 1))
 	int			verify_depth, session_timeout;
 #	else
 	long int		verify_depth, session_timeout;
 #	endif
+	long			options_mask, options_current, options_clear;
 	SSL_CTX			*ctx;
 	X509_STORE		*store;
 	X509_LOOKUP		*lookup;
@@ -274,8 +456,6 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
 			return NULL; /* Relevant error detail populated in the above macro. */
 	}
 	OpenSSL_add_all_algorithms();
-	OpenSSL_add_all_ciphers();
-	OpenSSL_add_all_digests();
 	/* Setup function pointers to symbols exported by libgtmshr.so. */
 	if (0 != gc_load_gtmshr_symbols())
 		return NULL;
@@ -308,6 +488,13 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
 	/* Get global SSL configuration parameters */
 	if (config_lookup_int(cfg, "tls.verify-depth", &verify_depth))
 		SSL_CTX_set_verify_depth(ctx, verify_depth);
+	if (CONFIG_TRUE == config_lookup_string(cfg, "tls.verify-mode", &verify_mode_string))
+	{
+		verify_mode = (int)parse_SSL_options(&gtm_ssl_verify_mode_list[0], SIZEOF(gtm_ssl_verify_mode_list),
+					verify_mode_string, (long)0, NULL);
+		SSL_CTX_set_verify(ctx, verify_mode, NULL);
+	} else
+		flags |= GTMTLS_OP_ABSENT_VERIFYMODE;
 	rv1 = config_lookup_string(cfg, "tls.CAfile", &CAfile);
 	rv2 = config_lookup_string(cfg, "tls.CApath", &CApath);
 	/* Setup trust locations for peer verifications. This adds on to any trust locations that was previously loaded. */
@@ -375,25 +562,43 @@ gtm_tls_ctx_t *gtm_tls_init(int version, int flags)
 			SSL_CTX_set_timeout(ctx, session_timeout);
 	} else
 		SSL_CTX_set_timeout(ctx, DEFAULT_SESSION_TIMEOUT);
-	if (0 >= SSL_CTX_set_cipher_list(ctx, CIPHER_LIST))
+	if (CONFIG_FALSE == config_lookup_string(cfg, "tls.cipher-list", &cipher_list))
+		cipher_list = NULL;
+	else if (('\0' != cipher_list[0]) && (0 >= SSL_CTX_set_cipher_list(ctx, cipher_list)))
 	{
-		GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", CIPHER_LIST);
+		GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", cipher_list);
 		SSL_CTX_free(ctx);
 		config_destroy(cfg);
 		return NULL;
+	}	/* use OpenSSL default */
+	if (CONFIG_TRUE == config_lookup_string(cfg, "tls.ssl-options", &options_string))
+	{
+		options_current = SSL_CTX_get_options(ctx);
+		options_clear = 0;
+		options_mask = parse_SSL_options(&gtm_ssl_options_list[0], SIZEOF(gtm_ssl_options_list), options_string,
+					options_current, &options_clear);
+		if (0 != options_mask)
+			options_mask = SSL_CTX_set_options(ctx, options_mask);
+		if (0 != options_clear)
+			options_mask = SSL_CTX_clear_options(ctx, options_clear);
 	}
 	gtm_tls_ctx = MALLOC(SIZEOF(gtm_tls_ctx_t));
 	gtm_tls_ctx->ctx = ctx;
+	if (NULL == cipher_list)
+		flags |= GTMTLS_OP_ABSENT_CIPHER;
+	else if ('\0' == cipher_list[0])
+		flags |= GTMTLS_OP_DEFAULT_CIPHER;
 	gtm_tls_ctx->flags = flags;
 	gtm_tls_ctx->fips_mode = fips_enabled;
 	gtm_tls_ctx->compile_time_version = OPENSSL_VERSION_NUMBER;
 	gtm_tls_ctx->runtime_version = SSLeay();
+	gtm_tls_ctx->version = version;
 	return gtm_tls_ctx;
 }
 
 void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
 {
-	char			*env_name_ptr, *env_value, prompt[256];
+	char			*env_name_ptr, *env_value, prompt[GTM_PASSPHRASE_MAX_ASCII + 1];
 	gtmtls_passwd_list_t	*pwent_node;
 	passwd_entry_t		*pwent;
 
@@ -404,7 +609,7 @@ void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
 	assert(PASSPHRASE_ENVNAME_MAX > STRLEN(env_name_ptr));
 	assert(SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1 < STRLEN(env_name_ptr));
 	env_name_ptr += (SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
-	SNPRINTF(prompt, 256, "Enter passphrase for TLSID %s: ", env_name_ptr);
+	SNPRINTF(prompt, GTM_PASSPHRASE_MAX_ASCII, "Enter passphrase for TLSID %s: ", env_name_ptr);
 	pwent = NULL;
 	if (0 == gc_update_passwd(env_name, &pwent, prompt, TRUE))
 	{
@@ -420,10 +625,16 @@ void gtm_tls_prefetch_passwd(gtm_tls_ctx_t *tls_ctx, char *env_name)
 
 gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_socket, int sockfd, char *id, int flags)
 {
-	int			len;
-	char			cfg_path[MAX_CONFIG_LOOKUP_PATHLEN], input_env_name[PASSPHRASE_ENVNAME_MAX], *env_name_ptr;
-	char			prompt[256];
-	const char		*cert, *private_key, *format;
+	int			len, verify_mode, verify_mode_set, nocert, nopkey;
+	long			options_mask, options_current, options_clear;
+#	if (((LIBCONFIG_VER_MAJOR == 1) && (LIBCONFIG_VER_MINOR >= 4)) || (LIBCONFIG_VER_MAJOR > 1))
+	int			verify_depth, session_timeout;
+#	else
+	long int		verify_depth, session_timeout;
+#	endif
+	char			cfg_path[MAX_CONFIG_LOOKUP_PATHLEN], input_env_name[PASSPHRASE_ENVNAME_MAX + 1], *env_name_ptr;
+	char			prompt[GTM_PASSPHRASE_MAX_ASCII + 1];
+	const char		*cert, *private_key, *format, *cipher_list, *options_string, *verify_mode_string;
 	FILE			*fp;
 	SSL			*ssl;
 	SSL_CTX			*ctx;
@@ -447,105 +658,191 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
 		return NULL;
 	}
 
-	if (VERIFY_PEER(flags))
+	if ('\0' != id[0])
+	{
+		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.verify-mode", id);
+		if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &verify_mode_string))
+		{
+			verify_mode = (int)parse_SSL_options(&gtm_ssl_verify_mode_list[0], SIZEOF(gtm_ssl_verify_mode_list),
+						verify_mode_string, (long)0, NULL);
+			if (SSL_VERIFY_PEER & verify_mode)
+				flags |= GTMTLS_OP_VERIFY_PEER;
+			verify_mode_set = TRUE;
+		} else if (GTMTLS_OP_ABSENT_VERIFYMODE & tls_ctx->flags)
+		{
+			verify_mode = (GTMTLS_OP_VERIFY_PEER & flags) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+			verify_mode_set = TRUE;
+		} else
+			verify_mode_set = FALSE;
+		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.cipher-list", id);
+		if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &cipher_list))
+		{
+			if ('\0' == cipher_list[0]) /* use default instead of tls.cipher-list if empty string */
+				cipher_list = (GTMTLS_OP_SOCKET_DEV & flags) ? SSL_DEFAULT_CIPHER_LIST : REPL_CIPHER_LIST;
+		} else
+			cipher_list = NULL;
+	} else if (!CLIENT_MODE(flags))
+	{	/* server mode needs certificate and thus tlsid */
+		UPDATE_ERROR_STRING("Server mode requires a certificate but no TLSID specified");
+		SSL_free(ssl);
+		return NULL;
+	} else
+	{
+		assert(GTMTLS_OP_SOCKET_DEV & flags);
+		cipher_list = NULL;
+		if (GTMTLS_OP_ABSENT_VERIFYMODE & tls_ctx->flags)
+		{
+			verify_mode = (GTMTLS_OP_VERIFY_PEER & flags) ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
+			verify_mode_set = TRUE;
+		} else
+			verify_mode_set = FALSE;
+	}
+	if (verify_mode_set)
+		SSL_set_verify(ssl, verify_mode, NULL);
+	if (NULL == cipher_list)
+	{	/* no cipher-list in labelled section or no section */
+		if (0 != ((GTMTLS_OP_ABSENT_CIPHER | GTMTLS_OP_DEFAULT_CIPHER) &tls_ctx->flags))
+		{	/* no or default cipher specified top level */
+			cipher_list = (GTMTLS_OP_SOCKET_DEV & flags) ? SSL_DEFAULT_CIPHER_LIST : REPL_CIPHER_LIST;
+		}
+	}
+	if ((NULL != cipher_list) && (0 >= SSL_set_cipher_list(ssl, cipher_list)))
+	{
+		GC_APPEND_OPENSSL_ERROR("Failed to add Cipher-List command string: %s.", cipher_list);
+		SSL_free(ssl);
+		return NULL;
+	}
+	if ('\0' != id[0])
 	{
 		/* First lookup the certificate and private key associated with the provided id in the configuration file. */
 		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.cert", id);
 		if (!config_lookup_string(cfg, cfg_path, &cert))
 		{
-			UPDATE_ERROR_STRING("Certificate corresponding to TLSID: %s not found in configuration file.", id);
-			SSL_free(ssl);
-			return NULL;
-		}
-
+			if (!CLIENT_MODE(flags))
+			{
+				UPDATE_ERROR_STRING("Certificate corresponding to TLSID: %s not found in configuration file.", id);
+				SSL_free(ssl);
+				return NULL;
+			} else
+				nocert = TRUE;
+		} else
+			nocert = FALSE;
 		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.key", id);
-		if (!config_lookup_string(cfg, cfg_path, &private_key))
+		if (config_lookup_string(cfg, cfg_path, &private_key))
 		{
-			UPDATE_ERROR_STRING("Private Key corresponding to TLSID: %s not found in configuration file.", id);
-			SSL_free(ssl);
-			return NULL;
-		}
-
+			if (nocert)
+			{
+				UPDATE_ERROR_STRING("Private key but no certificate corresponding to TLSID:"
+					" %s in configuration file.", id);
+				SSL_free(ssl);
+				return NULL;
+			}
+		} else if (!nocert)
+			private_key = cert;	/* assume both in one file */
 		/* Verify that the format, if specified, is of PEM type as that's the only kind we support now. */
 		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.format", id);
 		if (config_lookup_string(cfg, cfg_path, &format))
 		{
+			if (nocert)
+			{
+				UPDATE_ERROR_STRING("Format but no certificate corresponding to TLSID: %s in configuration file.",
+					id);
+				SSL_free(ssl);
+				return NULL;
+			}
 			if (((SIZEOF("PEM") - 1) != strlen(format))
-					|| (format[0] != 'P') || (format[1] != 'E') || (format[2] != 'M'))
+				|| (format[0] != 'P') || (format[1] != 'E') || (format[2] != 'M'))
 			{
 				UPDATE_ERROR_STRING("Unsupported format type %s found for TLSID: %s.", format, id);
 				SSL_free(ssl);
 				return NULL;
 			}
 		}
-		/* Setup the certificate to be used for this connection */
-		if (!SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM))
+		if (!nocert)
 		{
-			GC_APPEND_OPENSSL_ERROR("Failed to add certificate %s.", cert);
-			SSL_free(ssl);
-			return NULL;
-		}
-
-		/* Before setting up the private key, check-up on the password for the private key. */
-		SNPRINTF(input_env_name, PASSPHRASE_ENVNAME_MAX, GTMTLS_PASSWD_ENV_PREFIX "%s", id);
-		if (NULL != (pwent_node = gtmtls_passwd_listhead))
-		{	/* Lookup to see if we have already prefetched the password. */
-			while (NULL != pwent_node)
+			/* Setup the certificate to be used for this connection */
+			if (!SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM))
 			{
-				env_name_ptr = pwent_node->pwent->env_name;
-				len = STRLEN(env_name_ptr);
-				assert(len < PASSPHRASE_ENVNAME_MAX);
-				assert(len > SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
-				if ((len == STRLEN(input_env_name)) && (0 == strncmp(input_env_name, env_name_ptr, len)))
-					break;
-				pwent_node = pwent_node->next;
+				GC_APPEND_OPENSSL_ERROR("Failed to add certificate %s.", cert);
+				SSL_free(ssl);
+				return NULL;
 			}
-		}
-		if (NULL == pwent_node)
-		{	/* Lookup failed. Create a new entry for the given id. */
-			pwent = NULL;
-			SNPRINTF(prompt, 256, "Enter passphrase for TLSID %s:", id);
-			if (0 != gc_update_passwd(input_env_name, &pwent, prompt, GTMTLS_OP_INTERACTIVE_MODE & tls_ctx->flags))
+			/* Before setting up the private key, check-up on the password for the private key. */
+			SNPRINTF(input_env_name, PASSPHRASE_ENVNAME_MAX, GTMTLS_PASSWD_ENV_PREFIX "%s", id);
+			if (NULL != (pwent_node = gtmtls_passwd_listhead))
+			{	/* Lookup to see if we have already prefetched the password. */
+				while (NULL != pwent_node)
+				{
+					env_name_ptr = pwent_node->pwent->env_name;
+					len = STRLEN(env_name_ptr);
+					assert(len < PASSPHRASE_ENVNAME_MAX);
+					assert(len > SIZEOF(GTMTLS_PASSWD_ENV_PREFIX) - 1);
+					if ((len == STRLEN(input_env_name)) && (0 == strncmp(input_env_name, env_name_ptr, len)))
+						break;
+					pwent_node = pwent_node->next;
+				}
+			}
+			if (NULL == pwent_node)
+			{	/* Lookup failed. Create a new entry for the given id. */
+				pwent = NULL;
+				SNPRINTF(prompt, GTM_PASSPHRASE_MAX_ASCII, "Enter passphrase for TLSID %s:", id);
+				if (0 != gc_update_passwd(input_env_name, &pwent, prompt, 0))
+				{
+					SSL_free(ssl);
+					return NULL;
+				}
+				pwent_node = MALLOC(SIZEOF(gtmtls_passwd_list_t));
+				pwent_node->next = gtmtls_passwd_listhead;
+				pwent_node->pwent = pwent;
+				gtmtls_passwd_listhead = pwent_node;
+			} else
+				pwent = pwent_node->pwent;
+			assert((NULL != pwent) && (NULL != pwent_node));
+			/* Setup the private key corresponding to the certificate and the callback function to obtain
+		 	* the password for the key. We cannot use the much simpler SSL_use_PrivateKey file to load
+		 	* the private key file because we want fine grained control on the password callback mechanism.
+		 	* For this purpose, use the PEM_read_PrivateKey function which
+		 	* supports callbacks for individual private keys.
+		 	*/
+			fp = fopen(private_key, "r");
+			if (NULL != fp)
 			{
+				evp_pkey = PEM_read_PrivateKey(fp, &evp_pkey, &passwd_callback, pwent);
+				fclose(fp);
+			} else
+				evp_pkey = NULL;
+			if (NULL == evp_pkey)
+			{
+				if (NULL == fp)
+				{
+					UPDATE_ERROR_STRING("Private Key corresponding to TLSID:"
+						" %s - error opening file %s: %s.", id, private_key, strerror(errno));
+				} else if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
+				{	/* give clearer error if only cert given but it doesn't have the key */
+					UPDATE_ERROR_STRING("Private Key corresponding to TLSID:"
+						" %s not found in configuration file.", id);
+				} else
+				{
+					GC_APPEND_OPENSSL_ERROR("Failed to read private key %s.", private_key);
+				}
+				SSL_free(ssl);
+				return NULL;
+			}
+			if (!SSL_use_PrivateKey(ssl, evp_pkey))
+			{
+				GC_APPEND_OPENSSL_ERROR("Failed to use private key %s.", private_key);
+				SSL_free(ssl);
+				return NULL;
+			}
+			/* Verify that private key matches the certificate */
+			if (!SSL_check_private_key(ssl))
+			{
+				GC_APPEND_OPENSSL_ERROR("Consistency check failed for private key: %s and certificate: %s\n",
+						private_key, cert);
 				SSL_free(ssl);
 				return NULL;
 			}
-			pwent_node = MALLOC(SIZEOF(gtmtls_passwd_list_t));
-			pwent_node->next = gtmtls_passwd_listhead;
-			pwent_node->pwent = pwent;
-			gtmtls_passwd_listhead = pwent_node;
-		} else
-			pwent = pwent_node->pwent;
-		assert((NULL != pwent) && (NULL != pwent_node));
-		/* Setup the private key corresponding to the certificate and the callback function to obtain the password for the
-		 * key. We cannot use the much simpler SSL_use_PrivateKey file to load the private key file because we want fine
-		 * grained control on the password callback mechanism. For this purpose, use the PEM_read_PrivateKey function which
-		 * supports callbacks for individual private keys.
-		 */
-		fp = fopen(private_key, "r");
-		evp_pkey = PEM_read_PrivateKey(fp, &evp_pkey, &passwd_callback, pwent);
-		fclose(fp);	/* Close the file irrespective of whether the above function succeeded or failed. */
-		if (NULL == evp_pkey)
-		{
-			GC_APPEND_OPENSSL_ERROR("Failed to read private key %s.", private_key);
-			SSL_free(ssl);
-			return NULL;
-		}
-		if (!SSL_use_PrivateKey(ssl, evp_pkey))
-		{
-			GC_APPEND_OPENSSL_ERROR("Failed to use private key %s.", private_key);
-			SSL_free(ssl);
-			return NULL;
-		}
-		/* Verify that private key matches the certificate */
-		if (!SSL_check_private_key(ssl))
-		{
-			GC_APPEND_OPENSSL_ERROR("Consistency check failed for private key: %s and certificate: %s\n",
-							private_key, cert);
-			SSL_free(ssl);
-			return NULL;
 		}
-		SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
 	}
 	/* OpenSSL does not recommend enabling compression as the current state of the SSL/TLS protocol does not specify identifiers
 	 * for compression libraries thereby allowing for incompatibilities when different SSL/TLS implementations are used in the
@@ -561,7 +858,26 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
 	compression = SSL_COMP_get_compression_methods();
 	sk_SSL_COMP_zero(compression);
 #	endif
-	if (0 == (GTMTLS_OP_CLIENT_MODE & flags))
+	if ('\0' != id[0])
+	{
+		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.ssl-options", id);
+		if (CONFIG_TRUE == config_lookup_string(cfg, cfg_path, &options_string))
+		{
+			options_current = SSL_get_options(ssl);
+			options_clear = 0;
+			options_mask = parse_SSL_options(&gtm_ssl_options_list[0], SIZEOF(gtm_ssl_options_list), options_string,
+					options_current, &options_clear);
+			if (0 != options_mask)
+				options_mask = SSL_set_options(ssl, options_mask);
+			if (0 != options_clear)
+				options_mask = SSL_clear_options(ssl, options_clear);
+
+		}
+		SNPRINTF(cfg_path, MAX_CONFIG_LOOKUP_PATHLEN, "tls.%s.verify-depth", id);
+		if (CONFIG_TRUE == config_lookup_int(cfg, cfg_path, &verify_depth))
+			SSL_set_verify_depth(ssl, verify_depth);
+	}
+	if (!CLIENT_MODE(flags))
 	{	/* Socket created for server mode operation. Set a session ID context for session resumption at the time of
 		 * reconnection.
 		 */
@@ -572,10 +888,10 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
 			return NULL;
 		}
 		/* Set up Ephemeral Diffie-Hellman key exchange callback. This callback is invoked whenever, during the connection
-		 * time, OpenSSL requires Diffie-Hellman key parameters. The SSL_OP_SINGLE_DH_USE is turned on so that the same
-		 * private key is not used for each session. This means a little extra computation during the time of handshake, but
-		 * is recommended by the OpenSSL community.
-		 */
+	 	* time, OpenSSL requires Diffie-Hellman key parameters. The SSL_OP_SINGLE_DH_USE is turned on so that the same
+	 	* private key is not used for each session. This means a little extra computation during the time of handshake, but
+	 	* is recommended by the OpenSSL community.
+	 	*/
 		if (-1 == init_dhparams())
 		{
 			SSL_free(ssl);
@@ -602,6 +918,8 @@ gtm_tls_socket_t *gtm_tls_socket(gtm_tls_ctx_t *tls_ctx, gtm_tls_socket_t *prev_
 		socket = prev_socket;
 	socket->flags = flags;
 	socket->ssl = ssl;
+	socket->gtm_ctx = tls_ctx;
+	strncpy(socket->tlsid, (const char *)id, SIZEOF(socket->tlsid));
 	/* Now, store the `socket' structure in the `SSL' structure so that we can get it back in a callback that receives an
 	 * `SSL' structure. Ideally, we should be using SSL_set_ex_data/SSL_get_ex_data family of functions. But, these functions
 	 * operate on a specific index (obtained by calling SSL_get_ex_new_index). But, since the library should potentially
@@ -617,7 +935,7 @@ int gtm_tls_connect(gtm_tls_socket_t *socket)
 {
 	int		rv;
 
-	assert(socket->flags & GTMTLS_OP_CLIENT_MODE);
+	assert(CLIENT_MODE(socket->flags));
 	DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
 	if (NULL != socket->session)
 	{	/* Old session available. Reuse it. */
@@ -648,10 +966,20 @@ int gtm_tls_accept(gtm_tls_socket_t *socket)
 int gtm_tls_renegotiate(gtm_tls_socket_t *socket)
 {
 	int		rv;
+	gtm_tls_ctx_t	*tls_ctx;
 
 	DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
 	if (0 >= (rv = SSL_renegotiate(socket->ssl)))
 		return ssl_error(socket->ssl, rv);
+#	ifdef TLS_RENEGOTIATE_NO_HANDSHAKE
+	tls_ctx = socket->gtm_ctx;
+	assert(tls_ctx);
+	if (GTMTLS_OP_INTERACTIVE_MODE & tls_ctx->flags)
+	{	/* avoid hanging until client does I/O */
+		socket->flags |= GTMTLS_OP_RENEGOTIATE_REQUESTED;
+		return 0;
+	}
+#	endif
 	do
 	{
 		if (0 < (rv = SSL_do_handshake(socket->ssl)))
@@ -766,6 +1094,8 @@ int gtm_tls_get_conn_info(gtm_tls_socket_t *socket, gtm_tls_conn_info *conn_info
 			if (-1 == format_ASN1_TIME(X509_get_notAfter(peer), conn_info->not_after, MAX_TIME_STRLEN))
 				SNPRINTF(conn_info->not_after, MAX_TIME_STRLEN, "Bad certificate date");
 			X509_free(peer);
+			if (GTM_TLS_API_VERSION_SOCK <= socket->gtm_ctx->version)
+				conn_info->options = SSL_get_options(ssl);
 			return 0;
 		} else
 		{
@@ -811,9 +1141,8 @@ int gtm_tls_cachedbytes(gtm_tls_socket_t *socket)
 
 void gtm_tls_socket_close(gtm_tls_socket_t *socket)
 {
-	assert(socket);
 	tls_errno = 0;
-	if (NULL == socket->ssl)
+	if ((NULL == socket) || (NULL == socket->ssl))
 		return;
 	DBG_VERIFY_SOCK_IS_BLOCKING(GET_SOCKFD(socket->ssl));
 	/* Invoke SSL_shutdown to close the SSL/TLS connection. Although the protocol (and the OpenSSL library) supports
diff --git a/sr_unix/gtm_tls_impl.h b/sr_unix/gtm_tls_impl.h
index 82abc2d..39ef2e0 100644
--- a/sr_unix/gtm_tls_impl.h
+++ b/sr_unix/gtm_tls_impl.h
@@ -8,8 +8,8 @@
  *	the license, please stop and do not read further.	*
  *								*
  ****************************************************************/
-#ifndef _GTM_TLS_IMPL_H
-#define _GTM_TLS_IMPL_H
+#ifndef GTM_TLS_IMPL_H
+#define GTM_TLS_IMPL_H
 
 STATICFNDEF int format_ASN1_TIME(ASN1_TIME *tm, char *buf, int maxlen);
 STATICFNDEF int ssl_generic_vfy_callback(int preverify_ok, X509_STORE_CTX *ctx);
@@ -29,6 +29,7 @@ typedef struct gtmtls_passwd_list_struct
 
 #define GET_SOCKFD(TLS)			SSL_get_fd((SSL *)TLS)
 #define VERIFY_PEER(FLAGS)		(FLAGS & GTMTLS_OP_VERIFY_PEER)
+#define CLIENT_MODE(FLAGS)		(FLAGS & GTMTLS_OP_CLIENT_MODE)
 #define DEFAULT_SESSION_TIMEOUT		3600		/* Old sessions can be reused upto 1 hour since the creation time. */
 
 #ifdef DEBUG
diff --git a/sr_unix/gtm_tls_interface.h b/sr_unix/gtm_tls_interface.h
index e984308..7c60630 100644
--- a/sr_unix/gtm_tls_interface.h
+++ b/sr_unix/gtm_tls_interface.h
@@ -9,13 +9,14 @@
  *								*
  ****************************************************************/
 
-#ifndef _GTM_TLS_INTERFACE_H
-#define _GTM_TLS_INTERFACE_H
+#ifndef GTM_TLS_INTERFACE_H
+#define GTM_TLS_INTERFACE_H
 
-#ifndef _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
-#define _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
+#ifndef GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
+#define GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED
 
-#define GTM_TLS_API_VERSION		0x00000001
+#define GTM_TLS_API_VERSION		0x00000002
+#define GTM_TLS_API_VERSION_SOCK	0x00000002	/* when TLS sockets added */
 
 #define MAX_X509_LEN			256
 #define MAX_ALGORITHM_LEN		64
@@ -37,7 +38,16 @@
 #define GTMTLS_WANT_WRITE		-3
 
 #define GTMTLS_PASSWD_ENV_PREFIX	"gtmtls_passwd_"
+/* below also defined in gtmcrypt_util.h so prevent redefinition in gtm_tls_impl.h */
+#ifndef GTM_PASSPHRASE_MAX
+#define GTM_PASSPHRASE_MAX            512     /* obfuscated */
+#define GTM_PASSPHRASE_MAX_ASCII      (GTM_PASSPHRASE_MAX / 2)
+#elif GTM_PASSPHRASE_MAX != 512
+#error "GTM-E-GTMTLSINTERFACE different values for GTM_PASSPHRASE_MAX"
+#endif
 
+/* Note these flags may be in either the ctx or ssl structures but not all
+ * may have meaning in both. */
 /* Whether the library is loaded in an interactive environment so that password prompting can happen if needed. */
 #define GTMTLS_OP_INTERACTIVE_MODE	0x00000001
 /* Turn-on compression for SSL/TLS protocol. */
@@ -46,6 +56,18 @@
 #define GTMTLS_OP_CLIENT_MODE		0x00000004
 /* Peer verification is needed. */
 #define GTMTLS_OP_VERIFY_PEER		0x00000008
+/* Socket device */
+#define GTMTLS_OP_SOCKET_DEV		0x00000010
+/* No cipher list specifed at top tls level */
+#define GTMTLS_OP_ABSENT_CIPHER		0x00000020
+/* Default cipher list used */
+#define GTMTLS_OP_DEFAULT_CIPHER	0x00000040
+/* REPL_CIPHER_LIST used */
+#define GTMTLS_OP_REPL_CIPHER		0x00000080
+/* No verify mode specifed at top tls level */
+#define GTMTLS_OP_ABSENT_VERIFYMODE	0x00000100
+/* Server requested renegotiation without waiting for handshake */
+#define GTMTLS_OP_RENEGOTIATE_REQUESTED	0x00000200
 
 #define GTMTLS_IS_FIPS_MODE(CTX)	(TRUE == CTX->fips_mode)
 #define GTMTLS_RUNTIME_LIB_VERSION(CTX)	(CTX->runtime_version)
@@ -67,15 +89,11 @@ typedef struct gtm_tls_conn_info_struct
 	char		issuer[MAX_X509_LEN];		/* CA who issued the certificate. */
 	char		not_before[MAX_TIME_STRLEN];	/* Date before which the certificate is not valid. */
 	char		not_after[MAX_TIME_STRLEN];	/* Date after which the certificate is not valid. */
+	/* items after this added for GTM_TLS_API_VERSION_SOCK */
+	long		options;			/* bitmask of SSL options */
+	int		renegotiation_pending;		/* no handshake yet */
 } gtm_tls_conn_info;
 
-typedef struct gtm_tls_session_struct
-{
-	int			flags;
-	void			*ssl;
-	void			*session;
-} gtm_tls_socket_t;
-
 typedef struct gtm_tls_ctx_struct
 {
 	int			flags;
@@ -83,9 +101,19 @@ typedef struct gtm_tls_ctx_struct
 	unsigned long		compile_time_version;	/* OpenSSL version that this library is compiled with. */
 	unsigned long		runtime_version;	/* OpenSSL version that this library is currently running with. */
 	void			*ctx;
+	int			version;		/* GTM_TLS_API_VERSION */
 } gtm_tls_ctx_t;
 
-#endif	/* _GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED */
+typedef struct gtm_tls_session_struct
+{
+	int			flags;
+	void			*ssl;
+	void			*session;
+	char			tlsid[MAX_TLSID_LEN + 1];
+	gtm_tls_ctx_t		*gtm_ctx;
+} gtm_tls_socket_t;
+
+#endif	/* GTM_TLS_INTERFACE_DEFINITIONS_INCLUDED */
 
 /* Note: The below function prototypes should be kept in sync with the corresponding declarations/definitions in sr_unix/gtm_tls.h
  * and sr_unix/gtm_tls_funclist.h.
diff --git a/sr_unix/gtm_trigger.c b/sr_unix/gtm_trigger.c
index dd96b71..2732a05 100644
--- a/sr_unix/gtm_trigger.c
+++ b/sr_unix/gtm_trigger.c
@@ -91,6 +91,7 @@ GBLREF	mval			dollar_ztrap;
 GBLREF	mval			gtm_trigger_etrap;
 GBLREF	mstr			*dollar_ztname;
 GBLREF	mval			*dollar_ztdata;
+GBLREF	mval			*dollar_ztdelim;
 GBLREF	mval			*dollar_ztoldval;
 GBLREF	mval			*dollar_ztriggerop;
 GBLREF	mval			*dollar_ztupdate;
@@ -260,7 +261,7 @@ CONDITION_HANDLER(gtm_trigger_complink_ch)
 
 CONDITION_HANDLER(gtm_trigger_ch)
 {	/* Condition handler for trigger execution - This handler is pushed on first for a given trigger level, then
-	 * mdb_condition_handler is pushed on so will appearr multiple times as trigger depth increases. There is
+	 * mdb_condition_handler is pushed on so will appear multiple times as trigger depth increases. There is
 	 * always an mdb_condition_handler behind us for an earlier trigger level and we let it handle severe
 	 * errors for us as it gives better diagnostics (e.g. GTM_FATAL_ERROR dumps) in addition to the file core dump.
 	 */
@@ -449,7 +450,7 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
 	PUSH_MV_STENT(MVST_MSAV);
 	mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource;
 	mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource;
-	TREF(trigger_compile) = TRUE;		/* Set flag so compiler knows this is a special trigger compile */
+	TREF(trigger_compile) = TRUE;	/* Set flag so compiler knows this is a special trigger compile */
 	op_zcompile(&zcompprm, TRUE);	/* Compile but don't use $ZCOMPILE qualifiers */
 	TREF(trigger_compile) = FALSE;	/* compile_source_file() establishes handler so always returns */
 	if (0 != TREF(dollar_zcstatus))
@@ -472,7 +473,9 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
 #		ifdef GEN_TRIGLINKFAIL_ERROR
 		UNLINK(objname);				/* delete object before it can be used */
 #		endif
+		TREF(trigger_compile) = TRUE;			/* Overload flag so we know it is a trigger link */
 		op_zlink(&zlfile, (mval *)&literal_null);	/* need cast due to "extern const" attributes */
+		TREF(trigger_compile) = FALSE;			/* If doesn't return, condition handler will clear */
 		/* No return here if link fails for some reason */
 		trigdsc->rtn_desc.rt_adr = find_rtn_hdr(&trigdsc->rtn_desc.rt_name);
 		/* Verify can find routine we just put there. Catastrophic if not */
@@ -528,8 +531,8 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
 		if (0 != gtm_trigger_complink(trigdsc, TRUE))
 		{
 			PRN_ERROR;	/* Leave record of what error caused the compilation failure if any */
-			rts_error_csa(CSA_ARG(cs_addrs)
-				VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2, trigdsc->rtn_desc.rt_name.len, trigdsc->rtn_desc.rt_name.addr);
+			rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2,
+				trigdsc->rtn_desc.rt_name.len - 1, trigdsc->rtn_desc.rt_name.addr);
 		}
 	}
 	assert(trigdsc->rtn_desc.rt_adr);
@@ -608,6 +611,7 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
 		mv_st_ent->mv_st_cont.mvs_trigr.savextref.len = extnam_str.len;
 		mv_st_ent->mv_st_cont.mvs_trigr.ztname_save = dollar_ztname;
 		mv_st_ent->mv_st_cont.mvs_trigr.ztdata_save = dollar_ztdata;
+		mv_st_ent->mv_st_cont.mvs_trigr.ztdelim_save = dollar_ztdelim;
 		mv_st_ent->mv_st_cont.mvs_trigr.ztoldval_save = dollar_ztoldval;
 		mv_st_ent->mv_st_cont.mvs_trigr.ztriggerop_save = dollar_ztriggerop;
 		mv_st_ent->mv_st_cont.mvs_trigr.ztupdate_save = dollar_ztupdate;
@@ -618,17 +622,19 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
 		mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigdsc_last_save = trigdsc;
 		mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigprm_last_save = trigprm;
 #		endif
-		/* If this is a spanning node update, a spanning node condition handler may be at the front of the line. However,
-		 * the condition handler just behind it should be either mdb_condition_handler or ch_at_trigger_init.
+		/* If this is a spanning node or spanning region update, a spanning node/region condition handler may be ahead.
+		 * However, the handler just behind it should be either mdb_condition_handler or ch_at_trigger_init.
 		 */
 		assert(((0 == gtm_trigger_depth)
-			&& (((ch_at_trigger_init == ctxt->ch)
-			     || ((ch_at_trigger_init == (ctxt - 1)->ch)
-				 && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch))))))
-		       || ((0 < gtm_trigger_depth)
-			   && (((&mdb_condition_handler == ctxt->ch)
-				|| ((&mdb_condition_handler == (ctxt - 1)->ch)
-				    && ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)))))));
+				&& (((ch_at_trigger_init == ctxt->ch)
+					|| ((ch_at_trigger_init == (ctxt - 1)->ch)
+						&& ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+							|| (&gvcst_spr_kill_ch == ctxt->ch))))))
+			|| ((0 < gtm_trigger_depth)
+				&& (((&mdb_condition_handler == ctxt->ch)
+					|| ((&mdb_condition_handler == (ctxt - 1)->ch)
+						&& ((&gvcst_put_ch == ctxt->ch) || (&gvcst_kill_ch == ctxt->ch)
+							|| (&gvcst_spr_kill_ch == ctxt->ch)))))));
 		mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save = ctxt;
 		mv_st_ent->mv_st_cont.mvs_trigr.gtm_trigger_depth_save = gtm_trigger_depth;
 		if (0 == gtm_trigger_depth)
@@ -682,6 +688,7 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm)
 	/* Set new value of trigger ISVs. Previous values already saved in trigger base frame */
 	dollar_ztname = &trigdsc->rtn_desc.rt_name;
 	dollar_ztdata = (mval *)trigprm->ztdata_new;
+	dollar_ztdelim = (mval *)trigprm->ztdelim_new;
 	dollar_ztoldval = trigprm->ztoldval_new;
 	dollar_ztriggerop = (mval *)trigprm->ztriggerop_new;
 	dollar_ztupdate = trigprm->ztupdate_new;
diff --git a/sr_unix/gtm_trigger.h b/sr_unix/gtm_trigger.h
index edc84bf..ca486f5 100644
--- a/sr_unix/gtm_trigger.h
+++ b/sr_unix/gtm_trigger.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -30,19 +30,16 @@
  * if we are eligible for this unwind. If not, this is an out-of-design condition we need to protect
  * against.
  */
-#define TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND								\
-{													\
-	if (SFT_TRIGR & frame_pointer->type)								\
-	{												\
-		if (INTRPT_IN_TRIGGER_NOMANS_LAND == intrpt_ok_state)					\
-		{	/* Remove this errant frame and continue to restart */				\
-			DBGTRIGR((stderr, "%s: trigger-no-mans-land situation - removing trigger "	\
-				  "base frame\n", __FILE__));						\
-			gtm_trigger_fini(FALSE, FALSE);							\
-		} else											\
-			/* Bad mojo - not in trigger-no-mans-land - unknown issue to protect against */	\
-			GTMASSERT;									\
-	}												\
+#define TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND							\
+{												\
+	if (SFT_TRIGR & frame_pointer->type)							\
+	{											\
+		assertpro(INTRPT_IN_TRIGGER_NOMANS_LAND == intrpt_ok_state);			\
+		/* Remove this errant frame and continue to restart */				\
+		DBGTRIGR((stderr, "%s: trigger-no-mans-land situation - removing trigger "	\
+			  "base frame\n", __FILE__));						\
+		gtm_trigger_fini(FALSE, FALSE);							\
+	}											\
 }
 
 typedef enum
@@ -63,6 +60,7 @@ typedef struct
 						 */
 	const mval	*ztdata_new;		/* $Data status of trigger value being Set/Killed - points to a constant mval
 						 * in mtables.c */
+	const mval	*ztdelim_new;		/* mval to set into $ZTDELIM - points to a string pool entry */
 	const mval	*ztriggerop_new;	/* Opcode type invoking the trigger - points to a constant mval in mtables.c */
 	mval		*ztupdate_new;		/* mval to set into $ZTUPDATE.
 						 * Points to stringpool at "gtm_trigger" entry - is NOT updated by the function */
diff --git a/sr_unix/gtm_trigger_trc.h b/sr_unix/gtm_trigger_trc.h
index c199339..e0079df 100644
--- a/sr_unix/gtm_trigger_trc.h
+++ b/sr_unix/gtm_trigger_trc.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -21,11 +21,13 @@
 /* #include "have_crit.h" for DBGFPF/FFLUSH/INTRPT_IN_FFLUSH */
 /* #define DEBUG_TRIGR */
 #if defined(DEBUG_TRIGR) && defined(GTM_TRIGGER)
+# define DBGIFTRIGR(x) if (is_trigger) DBGFPF(x)
 # define DBGTRIGR(x) DBGFPF(x)
 # define DBGTRIGR_ONLY(x) x
 # include "gtm_stdio.h"
 # include "gtmio.h"
 #else
+# define DBGIFTRIGR(x)
 # define DBGTRIGR(x)
 # define DBGTRIGR_ONLY(x)
 #endif
diff --git a/sr_unix/gtmci.c b/sr_unix/gtmci.c
index 0bdfce2..a848d52 100644
--- a/sr_unix/gtmci.c
+++ b/sr_unix/gtmci.c
@@ -214,6 +214,7 @@ int gtm_is_main_thread()
 int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types, unsigned int *io_vars_mask,
 		unsigned int *has_ret_value)
 {
+	boolean_t		need_rtnobj_shm_free;
 	callin_entry_list	*entry;
 	mstr			label, routine;
 	int			has_return, i, len;
@@ -283,7 +284,10 @@ int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types,
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name));
 	lref_parse((unsigned char*)entry->label_ref.addr, &routine, &label, &i);
 	/* The 3rd argument is NULL because we will get lnr_adr via lab_proxy. */
-	if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL))
+	/* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+	 * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+	 */
+	if (!job_addr(&routine, &label, 0, (char **)&base_addr, NULL, &need_rtnobj_shm_free))
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
 	memset(&param_blk, 0, SIZEOF(param_blk));
 	param_blk.rtnaddr = (void *)base_addr;
@@ -521,6 +525,7 @@ int gtm_cij(const char *c_rtn_name, char **arg_blob, int count, int *arg_types,
 /* Common work-routine for gtm_ci() and gtm_cip() to drive callin */
 int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle, va_list temp_var)
 {
+	boolean_t		need_rtnobj_shm_free;
 	va_list			var;
 	callin_entry_list	*entry;
 	mstr			label, routine;
@@ -596,7 +601,10 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
 		entry = callin_handle;
 	lref_parse((unsigned char*)entry->label_ref.addr, &routine, &label, &i);
 	/* 3rd argument is NULL because we will get lnr_adr via lab_proxy */
-	if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL))
+	/* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+	 * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+	 */
+	if (!job_addr(&routine, &label, 0, (char **)&base_addr, NULL, &need_rtnobj_shm_free))
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
 	memset(&param_blk, 0, SIZEOF(param_blk));
 	param_blk.rtnaddr = (void *)base_addr;
diff --git a/sr_unix/gtmcrypt_interface.h b/sr_unix/gtmcrypt_interface.h
index 267d85f..1887daf 100644
--- a/sr_unix/gtmcrypt_interface.h
+++ b/sr_unix/gtmcrypt_interface.h
@@ -67,12 +67,12 @@ gtm_char_t	*gtmcrypt_strerror(void);
  * encryption and decryption state objects is that for every encryption and decryption operation the initial IV is used, effectively
  * reverting to the original state.
  *
- * Arguments:	handle	Pointer which should get pointed to the database encryption state object.
+ * Arguments:	handle	Pointer to the database encryption state object supplied by the caller and filled in by this routine.
  * 		hash	Hash of the key.
  * 		iv	Initialization vector to use for encryption or decryption.
  *
- * Returns:	0 if the key was found and database encryption and decryption state objects were initialized or existed already; -1
- * 		otherwise.
+ * Returns:	0 if the routine found the key, and either found existing database encryption and decryption state objects or
+ * 		initialized them; -1 otherwise.
  */
 gtm_status_t	gtmcrypt_init_db_cipher_context_by_hash(gtmcrypt_key_t *handle, gtm_string_t hash, gtm_string_t iv);
 /***********************************************************************************************************************************
@@ -82,13 +82,15 @@ gtm_status_t	gtmcrypt_init_db_cipher_context_by_hash(gtmcrypt_key_t *handle, gtm
  * relying on the same key require individual encryption and decryption state objects as their states evolve with each encryption or
  * decryption operation.
  *
- * Arguments:	handle		Pointer which should get pointed to the device encryption or decryption state object.
+ * Arguments:	handle		Pointer to the database encryption state object supplied by the caller and filled in by this
+ * 				routine.
  * 		keyname		Name of the key.
  * 		iv		Initialization vector to use for encryption or decryption.
  * 		operation	Flag indicating whether encryption or decryption is desired; use GTMCRYPT_OP_ENCRYPT or
  * 				GTMCRYPT_OP_DECRYPT, respectively.
  *
- * Returns:	0 if the key was found and device encryption or decryption state object was initialized; -1 otherwise.
+ * Returns:	0 if the routine found the key, and either found existing database encryption and decryption state objects or
+ *		initialized them; -1 otherwise.
  */
 gtm_status_t	gtmcrypt_init_device_cipher_context_by_keyname(gtmcrypt_key_t *handle, gtm_string_t keyname,
 				gtm_string_t iv, gtm_int_t operation);
@@ -98,18 +100,18 @@ gtm_status_t	gtmcrypt_init_device_cipher_context_by_keyname(gtmcrypt_key_t *hand
  * configuration file in case of devices, or a path to a database file otherwise.
  *
  * Arguments:	keyname		Name of the key.
- * 		hash_dest	Pointer to the location where the key's hash is to be copied.
+ * 		hash_dest	Pointer to the location for this routine to copy the key's hash.
  *
- * Returns:	0 if the key was found and key's hash was copied to the specified location; -1 otherwise.
+ * Returns:	0 if the routine found the key and copied its hash to the specified location; -1 otherwise.
  */
 gtm_status_t	gtmcrypt_obtain_db_key_hash_by_keyname(gtm_string_t keyname, gtm_string_t *hash_dest);
 /***********************************************************************************************************************************
  * Release the specified encryption or decryption state object, also releasing the decryption state if database encryption state is
  * specified.
  *
- * Arguments:	handle	Encryption or decryption state object to release.
+ * Arguments:   handle	Pointer to the encryption or decryption state object to release.
  *
- * Returns:	0 if the operation was successful; -1 otherwise.
+ * Returns:	0 if the operation succeeded; -1 otherwise.
  */
 gtm_status_t	gtmcrypt_release_key(gtmcrypt_key_t handle);
 /***********************************************************************************************************************************
@@ -124,17 +126,17 @@ gtm_status_t	gtmcrypt_release_key(gtmcrypt_key_t handle);
  * at. With Gcrypt, on the other hand, modifying the IV (iv_mode != GTMCRYPT_IV_CONTINUE) before an operation influences the
  * subsequent IV-non-modifying (iv_mode == GTMCRYPT_IV_CONTINUE) operations.
  *
- * Arguments:	handle			Encryption state object to use.
- * 		unencr_block		Block where unencrypted data is read from.
- * 		unencr_block_len	Length of the unencrypted (and encrypted) data block.
- * 		encr_block		Block where encrypted data is put into.
- * 		operation		Flag indicating whether encryption or decryption is desired; use GTMCRYPT_OP_ENCRYPT or
+ * Arguments:	handle			Encryption state object.
+ * 		unencr_block		Block of unencrypted data.
+ * 		unencr_block_len	Length of the unencrypted and encrypted data blocks.
+ * 		encr_block		Block of encrypted data.
+ * 		operation		Flag indicating whether to perform encryption or decryption; use GTMCRYPT_OP_ENCRYPT or
  * 					GTMCRYPT_OP_DECRYPT, respectively.
- * 		iv_mode			Flag indicating whether the initialization vector (IV) should be changed prior to the
- * 					operation; use GTMCRYPT_IV_CONTINUE to proceed without changing the IV, GTMCRYPT_IV_SET to
- * 					set the IV the value supplied in the iv argument, and GTMCRYPT_IV_RESET to reset the IV to
- * 					the value specified at initialization.
- * 		iv			Initialization vector to set the encryption state to when iv_mode is GTMCRYPT_IV_SET.
+ * 		iv_mode			Flag indicating whether to change the initialization vector (IV) prior to the operation; use
+ * 					GTMCRYPT_IV_CONTINUE to proceed without changing the IV, GTMCRYPT_IV_SET to set the IV the
+ * 					value supplied in the iv argument, and GTMCRYPT_IV_RESET to reset the IV to the value
+ * 					specified at initialization.
+ * 		iv			Initialization vector for the encryption state to take when iv_mode is GTMCRYPT_IV_SET.
  *
  * Returns:	0 if the operation succeeded; -1 otherwise.
  */
@@ -143,8 +145,8 @@ gtm_status_t	gtmcrypt_encrypt_decrypt(gtmcrypt_key_t handle, gtm_char_t *src_blo
 /***********************************************************************************************************************************
  * Compare the keys associated with two encryption or decryption state objects.
  *
- * Arguments:	handle1		First ecryption or decryption state object to use.
- * 		handle2		Second ecryption or decryption state object to use.
+ * Arguments:	handle1		First encryption or decryption state object.
+ * 		handle2		Second encryption or decryption state object.
  *
  * Returns:	1 if both encryption or decryption state objects use the same key; 0 otherwise.
  */
diff --git a/sr_unix/gtmcrypt_util.c b/sr_unix/gtmcrypt_util.c
index 560976b..b870932 100644
--- a/sr_unix/gtmcrypt_util.c
+++ b/sr_unix/gtmcrypt_util.c
@@ -52,9 +52,9 @@ GBLDEF gtm_free_fnptr_t			gtm_free_fnptr;
 
 #define Tcsetattr(FDESC, WHEN, TERMPTR, RC, ERRNO)									\
 {															\
-	sigset_t block_ttinout;												\
-	sigset_t oldset;												\
-	int rc;														\
+	sigset_t	block_ttinout;											\
+	sigset_t	oldset;												\
+	int		rc;												\
 															\
 	sigemptyset(&block_ttinout);											\
 	sigaddset(&block_ttinout, SIGTTIN);										\
@@ -113,9 +113,9 @@ void gtm_gcry_log_handler(void *opaque, int level, const char *fmt, va_list arg_
 	return;
 }
 
-int gc_read_passwd(char *prompt, char *buf, int maxlen)
+int gc_read_passwd(char *prompt, char *buf, int maxlen, void *tty)
 {
-	struct termios		new_tty, old_tty;
+	struct termios		new_tty, old_tty, *tty_copy;
 	int			fd, status, save_errno, istty, i, rv;
 	char			c;
 
@@ -126,11 +126,22 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
 	fd = fileno(stdin);
 	if (FALSE != (istty = isatty(fd)))
 	{	/* Turn off terminal echo. */
-		if (0 != (status = tcgetattr(fd, &old_tty)))
+		status = tcgetattr(fd, &old_tty);
+		if (0 != status)
 		{
-			UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(errno));
+			UPDATE_ERROR_STRING("Unable to set up terminal for safe password entry. Will not request passphrase. %s",
+				strerror(errno));
 			return -1;
 		}
+		if (NULL != tty)
+		{	/* In case a pointer was passed for the current terminal state, avoid a race condition with a potential
+			 * interrupt by first assigning a pointer for the allocated space to a local variable and only then
+			 * updating the passed-in pointer.
+			 */
+			tty_copy = (struct termios *)MALLOC(SIZEOF(struct termios));
+			memcpy(tty_copy, &old_tty, SIZEOF(struct termios));
+			*((struct termios **)tty) = tty_copy;
+		}
 		new_tty = old_tty;
 		new_tty.c_lflag &= ~ECHO;
 		/* GT.M terminal settings has ICANON and ICRNL turned-off. This causes the terminal to be treated
@@ -142,7 +153,8 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
 		Tcsetattr(fd, TCSAFLUSH, &new_tty, status, save_errno);
 		if (-1 == status)
 		{
-			UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(save_errno));
+			UPDATE_ERROR_STRING("Unable to set up terminal for safe password entry. Will not request passphrase. %s",
+				strerror(save_errno));
 			return -1;
 		}
 	}
@@ -181,7 +193,7 @@ int gc_read_passwd(char *prompt, char *buf, int maxlen)
 		Tcsetattr(fd, TCSAFLUSH, &old_tty, status, save_errno);
 		if (-1 == status)
 		{
-			UPDATE_ERROR_STRING("Failed to obtain passphrase from terminal. %s", strerror(save_errno));
+			UPDATE_ERROR_STRING("Unable to restore terminal settings. %s", strerror(save_errno));
 			return -1;
 		}
 	}
@@ -357,7 +369,7 @@ int gc_update_passwd(char *name, passwd_entry_t **ppwent, char *prompt, int inte
 		gc_freeup_pwent(pwent);
 		return -1;
 	}
-	if (-1 == gc_read_passwd(prompt, passwd, GTM_PASSPHRASE_MAX))
+	if (-1 == gc_read_passwd(prompt, passwd, GTM_PASSPHRASE_MAX, NULL))
 	{
 		gc_freeup_pwent(pwent);
 		return -1;
diff --git a/sr_unix/gtmcrypt_util.h b/sr_unix/gtmcrypt_util.h
index 9b32999..8457c06 100644
--- a/sr_unix/gtmcrypt_util.h
+++ b/sr_unix/gtmcrypt_util.h
@@ -8,8 +8,8 @@
  *	the license, please stop and do not read further.	*
  *								*
  ****************************************************************/
-#ifndef __GTMCRYPT_UTIL_H
-#define __GTMCRYPT_UTIL_H
+#ifndef GTMCRYPT_UTIL_H
+#define GTMCRYPT_UTIL_H
 
 #if !defined(DEBUG) && defined(assert)
 # undef assert
@@ -28,7 +28,9 @@
 #define MAX_GTMCRYPT_STR_ARG_LEN	256
 #define MAX_GTMCRYPT_ERR_STRLEN		2048
 
-#define GTM_PASSPHRASE_MAX		512
+/* next two defines also in gtm_tls_interface.h and should be kept in sync */
+#define GTM_PASSPHRASE_MAX		512	/* obfuscated */
+#define GTM_PASSPHRASE_MAX_ASCII	(GTM_PASSPHRASE_MAX / 2)
 #define PASSPHRASE_ENVNAME_MAX		64
 #define GTMCRYPT_DEFAULT_PASSWD_PROMPT	"Enter Passphrase: "
 
@@ -36,7 +38,6 @@
 
 #define GTMCRYPT_FIPS_ENV		"gtmcrypt_FIPS"
 
-
 #define GC_H2D(C, RES, MULT)							\
 {										\
 	if ((C >= 'A') && (C <= 'F'))						\
@@ -49,7 +50,6 @@
 		RES = -1;							\
 }
 
-
 /* Convert SOURCE, sequence of hexadecimal characters, into decimal representation. LEN denotes the length of the SOURCE string.
  * NOTE: Hexadecimal characters, presented in SOURCE string, has to be in upper case.
  */
@@ -198,7 +198,7 @@
 /* Libgcrypt specific error handling. */
 #define GC_APPEND_GCRY_ERROR(ERR, ...)											\
 {															\
-	char	*errptr, *end;												\
+	char *errptr, *end;												\
 															\
 	errptr = &gtmcrypt_err_string[0];										\
 	end = errptr + MAX_GTMCRYPT_ERR_STRLEN;										\
@@ -235,7 +235,7 @@ GBLREF	char			gtmcrypt_err_string[MAX_GTMCRYPT_ERR_STRLEN];
 
 int				gc_load_gtmshr_symbols(void);
 void 				gtm_gcry_log_handler(void *opaque, int level, const char *fmt, va_list arg_ptr);
-int				gc_read_passwd(char *prompt, char *buf, int maxlen);
+int				gc_read_passwd(char *prompt, char *buf, int maxlen, void *tty);
 int				gc_mask_unmask_passwd(int nparm, gtm_string_t *in, gtm_string_t *out);
 void				gc_freeup_pwent(passwd_entry_t *pwent);
 int 				gc_update_passwd(char *name, passwd_entry_t **ppwent, char *prompt, int interactive);
diff --git a/sr_unix/gtminstall.sh b/sr_unix/gtminstall.sh
index b8cdd1d..3e94416 100644
--- a/sr_unix/gtminstall.sh
+++ b/sr_unix/gtminstall.sh
@@ -263,6 +263,11 @@ case ${gtm_hostos}_${gtm_arch} in
         gtm_ftp_dirname="hpux_ia64"
         gtm_flavor="ia64"
         gtm_install_flavor="IA64" ;;
+    linux_i586) gtm_sf_dirname="GT.M-x86-Linux"
+        gtm_ftp_dirname="linux"
+        gtm_flavor="i586"
+        gtm_install_flavor="x86"
+        gtm_shlib_support="N" ;;
     linux_i686) gtm_sf_dirname="GT.M-x86-Linux"
         gtm_ftp_dirname="linux"
         gtm_flavor="i686"
diff --git a/sr_unix/gtminstall_Solaris.sh b/sr_unix/gtminstall_Solaris.sh
index 69a5f18..e81f579 100644
--- a/sr_unix/gtminstall_Solaris.sh
+++ b/sr_unix/gtminstall_Solaris.sh
@@ -263,6 +263,11 @@ case ${gtm_hostos}_${gtm_arch} in
         gtm_ftp_dirname="hpux_ia64"
         gtm_flavor="ia64"
         gtm_install_flavor="IA64" ;;
+    linux_i586) gtm_sf_dirname="GT.M-x86-Linux"
+        gtm_ftp_dirname="linux"
+        gtm_flavor="i586"
+        gtm_install_flavor="x86"
+        gtm_shlib_support="N" ;;
     linux_i686) gtm_sf_dirname="GT.M-x86-Linux"
         gtm_ftp_dirname="linux"
         gtm_flavor="i686"
diff --git a/sr_unix/gtmio.h b/sr_unix/gtmio.h
index b4dfabc..1a2c9a2 100644
--- a/sr_unix/gtmio.h
+++ b/sr_unix/gtmio.h
@@ -17,10 +17,8 @@
  *		Loop until open succeeds or fails with other than EINTR.
  *		Opens with O_DSYNC/O_SYNC in direct mode where possible.
  *		Else opens only with O_DSYNC or O_SYNC.
- * OPEN_OBJECT_FILE
- *		Opens the object file and waits till it gets a lock(shr/excl).
- *		Sets default perms if it creates a new file.
- * CLOSE_OBJECT_FILE - close the object file after releasing the lock on it.
+ * OPEN_OBJECT_FILE	Opens the object file.
+ * CLOSE_OBJECT_FILE	Close the object file.
  * CLOSEFILE	Loop until close succeeds for fails with other than EINTR.
  * CLOSEFILE_RESET
  * 		Loop until close succeeds for fails with other than EINTR.
@@ -193,10 +191,8 @@ error_def(ERR_PREMATEOF);
 #else
 #define LOCK_IS_ALLOWED(FDESC, STATUS)	STATUS = 0
 #endif
-#define OPEN_OBJECT_FILE(FNAME, FFLAG, FDESC)	FDESC = open_object_file(FNAME, FFLAG);
-
+#define OPEN_OBJECT_FILE(FNAME, FFLAG, FDESC)	OPENFILE(FNAME, FFLAG, FDESC)
 #define CLOSE_OBJECT_FILE(FDESC, RC)		CLOSEFILE_RESET(FDESC, RC)
-
 #define CLOSEFILE(FDESC, RC)					\
 {								\
 	do							\
@@ -616,7 +612,7 @@ error_def(ERR_PREMATEOF);
 		   the CHUNK_SIZE, no need to read once again since it is in BLOCKING mode, in which case it will return -1.	\
 		   So in the first read itself (after a successful read) break from the infinite loop. This variable is TRUE    \
 		   if DOREADRLTO2 macro is called for a CHUNK_SIZE read. In other places (eg: iorm_get) it will be FALSE.	\
-		   */											 	\
+		*/												\
 			if (UTF_VAR_PF)										\
 				break;										\
 		} else if (EINTR != errno || TOFLAG)								\
@@ -832,11 +828,4 @@ typedef struct
 	fflush(STREAM);					\
 	ENABLE_INTERRUPTS(INTRPT_IN_FFLUSH);		\
 }
-
-/* Prototypes */
-int open_object_file(const char *fname, int fflag);
-int mk_tmp_object_file(const char *object_fname, int object_fname_len);
-void rename_tmp_object_file(const char *object_fname);
-void init_object_file_name(void);
-
 #endif
diff --git a/sr_unix/gtmprofile.gtc b/sr_unix/gtmprofile.gtc
index 7e12f5e..c999109 100644
--- a/sr_unix/gtmprofile.gtc
+++ b/sr_unix/gtmprofile.gtc
@@ -164,12 +164,12 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
 	    if [ -d $gtm_dist/plugin/o/utf8 ] ; then
 		gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtm_dist")_"/plugin/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x) quit:""=y  write y," "'`"$gtm_dist/plugin/o/utf8($gtm_dist/plugin/r) $gtmroutines"
 	    fi
-            gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x)  quit:""=y  write y," "'`"$gtmdir/$gtmver/o/utf8($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
+            gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/utf8/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x)  quit:""=y  write y," "'`"$gtmdir/$gtmver/o/utf8*($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
 	else
 	    if [ -d $gtm_dist/plugin/o ] ; then
 		gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtm_dist")_"/plugin/o/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x) quit:""=y  write y," "'`"$gtm_dist/plugin/o($gtm_dist/plugin/r) $gtmroutines"
 	    fi
-            gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x)  quit:""=y  write y," "'`"$gtmdir/$gtmver/o($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
+            gtmroutines=`$gtm_dist/mumps -run %XCMD 'set x=$ztrnlnm("gtmdir")_"/"_$ztrnlnm("gtmver")_"/o/*."_$ztrnlnm("tmp_gtm_shlib") for  set y=$zsearch(x)  quit:""=y  write y," "'`"$gtmdir/$gtmver/o*($gtmdir/$gtmver/r $gtmdir/r) $gtmroutines"
 	fi
     fi
     export gtmroutines
@@ -253,6 +253,12 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
     if [ -z "$gtm_retention" ] ; then
         gtm_retention=42 ; export gtm_retention
     fi
+    # Set & uncomment these as required
+    # Refer to the GT.M Administration & Operations Guide for complete list of GT.M environment variables
+    # export gtm_autorelink_keeprtn=1	# leave auto-relinked object code in the shared memory repositories
+    # export gtm_linktmpdir=    	# put relinkctl files in location other than $gtm_tmp
+    # export gtm_baktmpdir=		# location for MUPIP BACKUP temporary snapshot files
+    # export gtm_snaptmpdir=		# location for MUPIP INTEG temporary snapshot files
 
     # Set environment variables for plugins in $gtm_dist/plugin
     tmp_gtm_tmp=`uname -s`
diff --git a/sr_unix/gtmrecv_process.c b/sr_unix/gtmrecv_process.c
index 35c1bdd..e0ebbe2 100644
--- a/sr_unix/gtmrecv_process.c
+++ b/sr_unix/gtmrecv_process.c
@@ -198,14 +198,12 @@ error_def(ERR_INSNOTJOINED);
 error_def(ERR_INSROLECHANGE);
 error_def(ERR_INSUNKNOWN);
 error_def(ERR_JNLNEWREC);
-error_def(ERR_JNLRECFMT);
 error_def(ERR_JNLSETDATA2LONG);
 error_def(ERR_NOSUPPLSUPPL);
 error_def(ERR_PRIMARYNOTROOT);
 error_def(ERR_RCVRMANYSTRMS);
 error_def(ERR_REPL2OLD);
 error_def(ERR_REPLCOMM);
-error_def(ERR_REPLGBL2LONG);
 error_def(ERR_REPLINSTNOHIST);
 error_def(ERR_REPLINSTREAD);
 error_def(ERR_REPLNOTLS);
@@ -213,7 +211,6 @@ error_def(ERR_REPLTRANS2BIG);
 error_def(ERR_REPLXENDIANFAIL);
 error_def(ERR_RESUMESTRMNUM);
 error_def(ERR_REUSEINSTNAME);
-error_def(ERR_SECNODZTRIGINTP);
 error_def(ERR_SECONDAHEAD);
 error_def(ERR_STRMNUMIS);
 error_def(ERR_SUPRCVRNEEDSSUPSRC);
@@ -486,11 +483,11 @@ STATICFNDEF int repl_tr_endian_convert(unsigned char remote_jnl_ver, uchar_ptr_t
 			}
 			if (IS_SET_KILL_ZKILL_ZTWORM_LGTRIG_ZTRIG(rectype))
 			{
-				/* This code will need changes in case the jnl-ver changes from V24 to V25 so add an assert to
+				/* This code will need changes in case the jnl-ver changes from V25 to V26 so add an assert to
 				 * alert to that possibility. Once the code is fixed for the new jnl format, change the assert
 				 * to reflect the new latest jnl-ver.
 				 */
-				assert(JNL_VER_THIS == V24_JNL_VER);
+				assert(JNL_VER_THIS == V25_JNL_VER);
 				/* To better understand the logic below (particularly the use of hardcoded offsets), see comment
 				 * in repl_filter.c (search for "struct_jrec_upd layout" for the various jnl versions we support).
 				 */
@@ -959,12 +956,13 @@ void	gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypest
  */
 void	gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, boolean_t is_rcvr_srvr)
 {
-	boolean_t		remote_side_is_supplementary, grab_lock_needed;
+	boolean_t		remote_side_is_supplementary, grab_lock_needed, lms_group_different;
 	repl_inst_hdr_ptr_t	inst_hdr;
 	repl_instinfo_msg_t	instinfo_msg;
 	repl_inst_uuid		*strm_start, *strm_top, *strm_info;
 	FILE			*log_fp;
 	int			reuse_slot, first_usable_slot;
+	uint4			creator_pid;
 	seq_num			strm_jnl_seqno;
 	sgmnt_addrs		*repl_csa;
 	DCL_THREADGBL_ACCESS;
@@ -975,8 +973,25 @@ void	gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
 	remote_side_is_supplementary = need_instinfo_msg->is_supplementary;
 	remote_side->is_supplementary = remote_side_is_supplementary;
 	assert(remote_side->endianness_known); /* ensure remote_side->cross_endian is reliable */
-	if (remote_side->cross_endian)
-		ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+	/* If the remote source server is <= V62000 it would have endian converted "need_instinfo_msg" ONLY IF
+	 * src_jnl_ver < rcv_jnl_ver. If remote source server is > V62000 it would have endian converted unconditionally.
+	 * So we dont need to do the endian conversion in either of those cases. The need_instinfo_msg->proto_ver will let
+	 * us distinguish the > V62000 vs <= V62000 case. But if src version is <= V62000, we cannot easily distinguish what
+	 * the other side's jnl_ver is so we dont know if the source server would have endian converted or not. We work around
+	 * it by assuming that pids are limited to a max of 2**24 and so the most significant byte of the 4-byte pid should be 0.
+	 * This trick might not work always in case an OS supports > 2**24 pid number (I dont know of any now) OR if both the
+	 * most and least significant bytes of the 4-byte pid are 0, but if it does not, the worst we will see is a) an incorrect
+	 * INSNOTJOINED error issued by the receiver server OR b) an incorrect lms_group_info copied over into the instance file
+	 * (which will soon elicit some other related error). We can address (a) by trying out endian converting again below to
+	 * see if that prevents the error and if so use that instead but we cannot address (b) with this trick.
+	 * We can live with since the fix for (b) is to upgrade the receiver side to GTM V62001 or higher.
+	 */
+	if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES > need_instinfo_msg->proto_ver))
+	{
+		creator_pid = need_instinfo_msg->lms_group_info.creator_pid;
+		if (!(creator_pid & 0xff) && (creator_pid & 0xff000000))
+			ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+	}
 	assert(is_rcvr_srvr && (NULL != gtmrecv_log_fp) || !is_rcvr_srvr && (NULL == gtmrecv_log_fp));
 	assert(!is_rcvr_srvr || !repl_csa->hold_onto_crit);
 	assert(is_rcvr_srvr || !jgbl.onlnrlbk || repl_csa->hold_onto_crit);
@@ -1045,7 +1060,26 @@ void	gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
 		if (memcmp(&need_instinfo_msg->lms_group_info, &inst_hdr->lms_group_info, SIZEOF(inst_hdr->lms_group_info)))
 		{	/* Source and Receiver are part of DIFFERENT LMS Groups. If this instance is supplementary and remote
 			 * side is not supplementary then we expect them to be different. Otherwise issue error.
+			 * Note that because of an issue with endian-conversion (see big comment at start of this function),
+			 * it is possible this lms_group_info would be good (i.e. passed the memcmp) if endian-converted. So
+			 * try that once and if it still fails, go ahead with issuing an error.
 			 */
+			lms_group_different = TRUE;
+			if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES > need_instinfo_msg->proto_ver))
+			{
+				ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+				if (!memcmp(&need_instinfo_msg->lms_group_info,
+						&inst_hdr->lms_group_info, SIZEOF(inst_hdr->lms_group_info)))
+					lms_group_different = FALSE;	/* stay with converted lms_group_info as it is good */
+				else
+				{	/* neither works so return to the original */
+					ENDIAN_CONVERT_REPL_INST_UUID(&need_instinfo_msg->lms_group_info);
+				}
+			}
+		} else
+			lms_group_different = FALSE;
+		if (lms_group_different)
+		{
 			if (!inst_hdr->is_supplementary || remote_side_is_supplementary)
 			{
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSNOTJOINED, 4,
@@ -1781,23 +1815,17 @@ STATICFNDEF void process_tr_buff(int msg_type)
 						write_len = out_size;
 					else
 					{
-						assert(EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno);
-						if (EREPL_INTLFILTER_BADREC == repl_errno)
-							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLRECFMT);
-						else if (EREPL_INTLFILTER_DATA2LONG == repl_errno)
+						if (EREPL_INTLFILTER_DATA2LONG == repl_errno)
 							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLSETDATA2LONG, 2,
 									jnl_source_datalen, jnl_dest_maxdatalen);
 						else if (EREPL_INTLFILTER_NEWREC == repl_errno)
 							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNLNEWREC, 2,
 									(unsigned int)jnl_source_rectype,
 									(unsigned int)jnl_dest_maxrectype);
-						else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
-							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);
-						else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
-							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1,
-									&recvpool_ctl->jnl_seqno);
-						else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */
-							assertpro(repl_errno != repl_errno);
+						else
+						{
+							INT_FILTER_RTS_ERROR(recvpool_ctl->jnl_seqno, repl_errno); /* no return */
+						}
 					}
 				} else
 					memcpy(repl_filter_buff, recvpool.recvdata_base + write_off, write_len);
@@ -2677,7 +2705,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 	boolean_t			uncmpfail, send_cross_endian, recvpool_prepared, copied_to_recvpool;
 	gtmrecv_local_ptr_t		gtmrecv_local;
 	gtm_time4_t			ack_time;
-	int4				msghdrlen, strm_num;
+	int4				msghdrlen, strm_num, processed_hdrlen;
 	int4				need_histinfo_num;
 	int				cmpret;
 	int				msg_type, msg_len;
@@ -2860,8 +2888,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 				DO_FLOW_CONTROL(write_loc);
 			}
 			if (xoff_sent && GTMRECV_XOFF_LOG_CNT <= xoff_msg_log_cnt)
-			{	/* update process is still running slow, Force wait before logging any message. */
-				SHORT_SLEEP(REPL_POLL_WAIT >> 10); /* approximate in ms */
+			{	/* Update process is still running slow; force wait before logging any message. */
+				SHORT_SLEEP(MILLISECS_IN_SEC - 1); /* Sleep for one second. */
 				REPL_DPRINT1("Waiting for Update Process to clear recvpool space\n");
 				xoff_msg_log_cnt = 0;
 			} else if (xoff_sent)
@@ -2936,7 +2964,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 				msg_type = (((repl_msg_ptr_t)buffp)->type & REPL_TR_CMP_MSG_TYPE_MASK);
 				if (REPL_TR_CMP_JNL_RECS == msg_type)
 				{
-					msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
+					processed_hdrlen = REPL_MSG_HDRLEN;
+					msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
 					gtmrecv_repl_cmpmsglen = msg_len;
 					gtmrecv_repl_uncmpmsglen = (((repl_msg_ptr_t)buffp)->type >> REPL_TR_CMP_MSG_TYPE_BITS);
 					assert(0 < gtmrecv_repl_uncmpmsglen);
@@ -2945,9 +2974,9 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 					 * since 8-byte aligned length would have been sent by the source server anyways.
 					 */
 					msg_len = ROUND_UP(msg_len, REPL_MSG_ALIGN);
-					buffp += REPL_MSG_HDRLEN;
+					buffp += processed_hdrlen;
 					exp_data_len = gtmrecv_repl_uncmpmsglen;
-					buff_unprocessed -= REPL_MSG_HDRLEN;
+					buff_unprocessed -= processed_hdrlen;
 					GTMRECV_SET_BUFF_TARGET_CMPBUFF(gtmrecv_repl_cmpmsglen, gtmrecv_repl_uncmpmsglen,
 						gtmrecv_cur_cmpmsglen);
 				} else if (REPL_TR_CMP_JNL_RECS2 == msg_type)
@@ -2958,6 +2987,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 					if (msghdrlen > buff_unprocessed)	/* Did not receive the full-header.            */
 						break;				/* Break out of here and read more data first. */
 					msghdrlen = REPL_MSG_HDRLEN; /* reset to regular msg hdr length for future messages */
+					processed_hdrlen = REPL_MSG_HDRLEN2;
 					cmpmsgp = (repl_cmpmsg_ptr_t)buffp;
 					if (remote_side->cross_endian)
 					{
@@ -2968,16 +2998,17 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 					gtmrecv_repl_uncmpmsglen = cmpmsgp->uncmplen;
 					assert(0 < gtmrecv_repl_uncmpmsglen);
 					assert(REPL_TR_CMP_THRESHOLD <= gtmrecv_repl_uncmpmsglen);
-					msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN2;
+					msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
 					/* Unlike REPL_TR_CMP_JNL_RECS message, msg_len is guaranteed to be 8-byte aligned here */
-					buffp += REPL_MSG_HDRLEN2;
+					buffp += processed_hdrlen;
 					exp_data_len = gtmrecv_repl_uncmpmsglen;
-					buff_unprocessed -= REPL_MSG_HDRLEN2;
+					buff_unprocessed -= processed_hdrlen;
 					GTMRECV_SET_BUFF_TARGET_CMPBUFF(gtmrecv_repl_cmpmsglen, gtmrecv_repl_uncmpmsglen,
 						gtmrecv_cur_cmpmsglen);
 				} else
 				{
-					msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
+					processed_hdrlen = REPL_MSG_HDRLEN;
+					msg_len = ((repl_msg_ptr_t)buffp)->len - processed_hdrlen;
 					exp_data_len = msg_len;
 					if (REPL_TR_JNL_RECS == msg_type || REPL_OLD_TRIPLE == msg_type || REPL_HISTREC == msg_type)
 					{
@@ -2991,8 +3022,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 						PREPARE_RECVPOOL_FOR_WRITE(exp_data_len, 0);
 						DEBUG_ONLY(recvpool_prepared = TRUE);
 					} /* for REPL_TR_CMP_JNL_RECS{2}, receive pool is prepared after uncompression */
-					buffp += REPL_MSG_HDRLEN;
-					buff_unprocessed -= REPL_MSG_HDRLEN;
+					buffp += processed_hdrlen;
+					buff_unprocessed -= processed_hdrlen;
 				}
 				assert(0 <= buff_unprocessed);
 				assert(0 == (msg_len % REPL_MSG_ALIGN));
@@ -3477,13 +3508,6 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 						assert(IF_INVALID != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
 						assert(IF_NONE != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
 						gtmrecv_filter |= INTERNAL_FILTER;
-						/* Any time the ^#t global format version is bumped, the below
-						 * assert will trip. This way, anyone who bumps the trigger label
-						 * ensures that the internal filter routines in repl_filter.c are
-						 * accordingly changed to upgrade triggers before applying them
-						 * on the current database which supports the latest ^#t format.
-						 */
-						assert(0 == MEMCMP_LIT(HASHT_GBL_CURLABEL, "2"));
 						gtmrecv_alloc_filter_buff(gtmrecv_max_repl_msglen);
 					} else
 					{
@@ -3662,8 +3686,8 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
 				buff_unprocessed += buffered_data_len;
 				data_len += buffered_data_len;
 				if (buffp_start != buff_start)
-					memmove(buff_start, buffp_start, buff_unprocessed + REPL_MSG_HDRLEN);
-				buffp = buff_start + REPL_MSG_HDRLEN; /* + REPL_MSG_HDRLEN since we already processed the header. */
+					memmove(buff_start, buffp_start, buff_unprocessed + processed_hdrlen);
+				buffp = buff_start + processed_hdrlen;
 			} else if (0 != buff_unprocessed)
 			{	/* We have an incomplete header. Move it to the beginning of the allocated buffer space. */
 				memmove(buff_start, buffp, buff_unprocessed);
diff --git a/sr_unix/gtmsecshr.c b/sr_unix/gtmsecshr.c
index 42e536e..84750e6 100644
--- a/sr_unix/gtmsecshr.c
+++ b/sr_unix/gtmsecshr.c
@@ -312,7 +312,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
 	gtmsecshr_mesg	mesg;
 	struct stat	stat_buf;
 	char		*gtm_tmp_ptr;
-	int		rc;
+	int		status;
 	int		lib_gid;
 	struct stat	dist_stat_buff;
 #	ifdef _AIX
@@ -452,8 +452,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
 					realpathbef[reclen-- - 1] = '\0';	/* Overwrite nl with null and decr length */
 				newtz = malloc(reclen);				/* putenv arg must be new - no stack vars */
 				strcpy(newtz, realpathbef);
-				rc = putenv(newtz);
-				if (0 != rc)
+				PUTENV(status, newtz);
+				if (0 != status)
 				{
 					save_errno = errno;
 					send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
@@ -507,9 +507,9 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
 	/* Close standard IO devices - we don't need/want them as all IO goes to operator log. Else we would have IO devices
 	 * tied to whatever process started gtmsecshr up which we definitely don't want.
 	 */
-	CLOSEFILE(0, rc);	/* No stdin */
-	CLOSEFILE(1, rc);	/* No stdout */
-	CLOSEFILE(2, rc);	/* No stderr */
+	CLOSEFILE(0, status);	/* No stdin */
+	CLOSEFILE(1, status);	/* No stdout */
+	CLOSEFILE(2, status);	/* No stderr */
 	/* Init signal handling which works slightly different than in other utilities - gtmsecshr has its own handler which
 	 * *calls* generic_signal_handler (which always returns for gtmsecshr) - we then drive our normal exit handling.
 	 */
@@ -519,7 +519,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
 	{	/* Close the file only if we have it open. This is to avoid a CLOSEFAIL error in case of
 		 * trying to close an invalid file descriptor.
 		 */
-		CLOSEFILE_IF_OPEN(file_des, rc);
+		CLOSEFILE_IF_OPEN(file_des, status);
 	}
 	if (-1 == CHDIR(P_tmpdir))	/* Switch to temporary directory as CWD */
 	{
diff --git a/sr_unix/gtmsource.c b/sr_unix/gtmsource.c
index dc6a7f5..6d46812 100644
--- a/sr_unix/gtmsource.c
+++ b/sr_unix/gtmsource.c
@@ -381,6 +381,7 @@ int gtmsource()
 		sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment);
 		repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
 	}
+	gtmsource_local->jnlfileonly = gtmsource_options.jnlfileonly;
 	do
 	{ 	/* If mode is passive, go to sleep. Wakeup every now and then and check to see if I have to become active. */
 		gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_START;
@@ -420,7 +421,7 @@ int gtmsource()
 		}
 		QWASSIGN(gtmsource_local->read_addr, jnlpool.jnlpool_ctl->write_addr);
 		gtmsource_local->read = jnlpool.jnlpool_ctl->write;
-		gtmsource_local->read_state = READ_POOL;
+		gtmsource_local->read_state = gtmsource_local->jnlfileonly ? READ_FILE : READ_POOL;
 		read_jnl_seqno = gtmsource_local->read_jnl_seqno;
 		assert(read_jnl_seqno <= jnlpool.jnlpool_ctl->jnl_seqno);
 		if (read_jnl_seqno < jnlpool.jnlpool_ctl->jnl_seqno)
diff --git a/sr_unix/gtmsource.h b/sr_unix/gtmsource.h
index 4ccf6b6..8514df8 100644
--- a/sr_unix/gtmsource.h
+++ b/sr_unix/gtmsource.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ *	Copyright 2006, 2014 Fidelity Information Services, Inc.*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -31,10 +31,6 @@
  */
 #define MERRORS_ARRAY_SZ		(2 * 1024)	/* 2k should be enough for a while */
 
-#ifdef VMS
-#define MAX_GSEC_KEY_LEN		32 /* 31 is allowed + 1 for NULL terminator */
-#endif
-
 enum
 {
 	READ_POOL,
@@ -350,10 +346,12 @@ typedef struct
 	int4			shutdown_time;		/* Time allowed for shutdown in seconds */
 	char			filter_cmd[MAX_FILTER_CMD_LEN];	/* command to run to invoke the external filter (if needed) */
 	global_latch_t		gtmsource_srv_latch;
+	boolean_t		jnlfileonly;		/* Current source server is only reading from journal files */
 #	ifdef GTM_TLS
 	uint4			next_renegotiate_time;	/* Time (in future) at which the next SSL/TLS renegotiation happens. */
 	int4			num_renegotiations;	/* Number of SSL/TLS renegotiations that happened so far. */
 #	endif
+	int4			padding;		/* Keep size % 8 == 0 */
 } gtmsource_local_struct;
 
 #if defined(__osf__) && defined(__alpha)
@@ -387,14 +385,6 @@ typedef gtmsource_local_struct *gtmsource_local_ptr_t;
 #define	JNLPOOL_CRIT_SIZE	(JNLPOOL_CRIT_SPACE + SIZEOF(mutex_spin_parms_struct) + SIZEOF(node_local))
 #define JNLDATA_BASE_OFF	(JNLPOOL_CTL_SIZE + JNLPOOL_CRIT_SIZE + REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE + GTMSOURCE_LOCAL_SIZE)
 
-#ifdef VMS
-typedef struct
-{
-	char			name[MAX_GSEC_KEY_LEN];
-	struct dsc$descriptor_s desc;
-} t_vms_shm_key;
-#endif
-
 /* the below structure has various fields that point to different sections of the journal pool */
 typedef struct
 {
@@ -405,11 +395,6 @@ typedef struct
 	repl_inst_hdr_ptr_t	repl_inst_filehdr;	/* pointer to the instance file header section in the journal pool */
 	gtmsrc_lcl_ptr_t	gtmsrc_lcl_array;	/* pointer to the gtmsrc_lcl array section in the journal pool */
 	sm_uc_ptr_t		jnldata_base;		/* pointer to the start of the actual journal record data */
-#ifdef VMS
-	sm_uc_ptr_t		shm_range[2];
-	t_vms_shm_key		vms_jnlpool_key;
-	int4			shm_lockid;
-#endif
 } jnlpool_addrs;
 
 #if defined(__osf__) && defined(__alpha)
@@ -459,6 +444,7 @@ typedef struct
 	boolean_t	setfreeze;	/* TRUE if -FREEZE was specified with a value, FALSE otherwise */
 	boolean_t	freezeval;	/* TRUE for -FREEZE=ON, FALSE for -FREEZE=OFF */
 	boolean_t	setcomment;	/* TRUE if -COMMENT was specified, FALSE otherwise */
+	boolean_t	jnlfileonly;	/* TRUE if -JNLFILEONLY was specified, FALSE otherwise */
 	int4		cmplvl;
 	int4		shutdown_time;
 	int4		buffsize;
diff --git a/sr_unix/gtmsource_get_opt.c b/sr_unix/gtmsource_get_opt.c
index 51478df..eaf9eff 100644
--- a/sr_unix/gtmsource_get_opt.c
+++ b/sr_unix/gtmsource_get_opt.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ *	Copyright 2006, 2014 Fidelity Information Services, Inc.*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -470,5 +470,6 @@ int gtmsource_get_opt(void)
 		else
 			gtmsource_options.showfreeze = TRUE;
 	}
+	gtmsource_options.jnlfileonly = (CLI_PRESENT == cli_present("JNLFILEONLY"));
 	return(0);
 }
diff --git a/sr_unix/gtmsource_process.c b/sr_unix/gtmsource_process.c
index 07d8f03..339709d 100644
--- a/sr_unix/gtmsource_process.c
+++ b/sr_unix/gtmsource_process.c
@@ -220,13 +220,9 @@ error_def(ERR_JNLNEWREC);
 error_def(ERR_JNLSETDATA2LONG);
 error_def(ERR_REPLCOMM);
 error_def(ERR_REPLFTOKSEM);
-error_def(ERR_REPLGBL2LONG);
 error_def(ERR_REPLINSTNOHIST);
-error_def(ERR_REPLNOMULTILINETRG);
 error_def(ERR_REPLNOTLS);
-error_def(ERR_REPLRECFMT);
 error_def(ERR_REPLXENDIANFAIL);
-error_def(ERR_SECNODZTRIGINTP);
 error_def(ERR_TRIG2NOTRIG);
 error_def(ERR_TLSRENEGOTIATE);
 error_def(ERR_TEXT);
@@ -1090,11 +1086,6 @@ int gtmsource_process(void)
 			else
 				remote_side->null_subs_xform = FALSE;
 			gtmsource_filter |= INTERNAL_FILTER;
-			/* Any time the ^#t global format version is bumped, the below assert will trip. This way, anyone who bumps
-			 * the trigger label ensures that the internal filter routines in repl_filter.c are accordingly changed to
-			 * downgrade triggers before sending them across to a receiver that understands ONLY the prior ^#t format.
-			 */
-			assert(0 == MEMCMP_LIT(HASHT_GBL_CURLABEL, "2"));
 			gtmsource_alloc_filter_buff(gtmsource_msgbufsiz);
 		} else
 		{
@@ -1540,12 +1531,8 @@ int gtmsource_process(void)
 							 * do at this point.
 							 */
 							assert(intfilter_error);
-							assert((EREPL_INTLFILTER_BADREC == repl_errno)
-								|| (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
-								|| (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
-								|| (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno));
 							assert(filter_seqno == pre_read_seqno);
-							INT_FILTER_RTS_ERROR(filter_seqno); /* no return */
+							INT_FILTER_RTS_ERROR(filter_seqno, repl_errno); /* no return */
 						}
 					}
 					assert(send_tr_len && (0 == (send_tr_len % REPL_MSG_ALIGN)));
@@ -1671,12 +1658,8 @@ int gtmsource_process(void)
 						 * the receiever server will communicate the appropriate sequence number as
 						 * part of the histinfo exchange.
 						 */
-						assert((EREPL_INTLFILTER_BADREC == repl_errno)
-							|| (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
-							|| (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
-							|| (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno));
 						assert(filter_seqno <= post_read_seqno);
-						INT_FILTER_RTS_ERROR(filter_seqno); /* no return */
+						INT_FILTER_RTS_ERROR(filter_seqno, repl_errno); /* no return */
 					}
 					jnlpool.gtmsource_local->read_jnl_seqno = post_read_seqno;
 					if (GTMSOURCE_FH_FLUSH_INTERVAL <= difftime(gtmsource_now, gtmsource_last_flush_time))
diff --git a/sr_unix/gtmsource_process_ops.c b/sr_unix/gtmsource_process_ops.c
index 8646799..58b2f46 100644
--- a/sr_unix/gtmsource_process_ops.c
+++ b/sr_unix/gtmsource_process_ops.c
@@ -1384,11 +1384,16 @@ boolean_t	gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_
 		needinst_msg.lms_group_info = jnlpool.repl_inst_filehdr->lms_group_info;
 		/* Need to byteswap a few multi-byte fields to take into account the receiver endianness */
 		assert(remote_side->endianness_known);	/* only then is remote_side->cross_endian reliable */
-		if (remote_side->cross_endian && (this_side->jnl_ver < remote_side->jnl_ver))
+		/* Starting GT.M V62001, the receiver server expects an endian converted lms_group_info. So endian
+		 * convert in that case. Pre-V62001, the receiver unconditionally did the endian conversion. So skip
+		 * endian conversion in the source side in that case.
+		 */
+		if (remote_side->cross_endian && (REPL_PROTO_VER_XENDIANFIXES <= remote_side->proto_ver))
 			ENDIAN_CONVERT_REPL_INST_UUID(&needinst_msg.lms_group_info);
 		needinst_msg.proto_ver = REPL_PROTO_VER_THIS;
 		needinst_msg.is_rootprimary = !(jnlpool.jnlpool_ctl->upd_disabled);
 		needinst_msg.is_supplementary = jnlpool.repl_inst_filehdr->is_supplementary;
+		needinst_msg.jnl_ver = JNL_VER_THIS;
 		gtmsource_repl_send((repl_msg_ptr_t)&needinst_msg, "REPL_NEED_INSTINFO", MAX_SEQNO, INVALID_SUPPL_STRM);
 		if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state))
 			return FALSE; /* send did not succeed */
diff --git a/sr_unix/gtmsource_readfiles.c b/sr_unix/gtmsource_readfiles.c
index 9ed8342..014776c 100644
--- a/sr_unix/gtmsource_readfiles.c
+++ b/sr_unix/gtmsource_readfiles.c
@@ -814,7 +814,7 @@ static void increase_buffer(unsigned char **buff, int *buflen, int buffer_needed
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
 			  LEN_AND_LIT("Error extending buffer space while reading files. Malloc error"), alloc_status);
 	}
-	REPL_DPRINT3("Old gtmsource_msgp = 0x%llx; New gtmsource_msgp = 0x%llx\n", (long long)old_msgp, (long long)gtmsource_msgp);
+	REPL_DPRINT3("Old gtmsource_msgp = 0x%llx; New gtmsource_msgp = 0x%llx\n", old_msgp, gtmsource_msgp);
 	REPL_DPRINT2("Old *buff = 0x%llx\n", *buff);
 	*buff = (unsigned char *)gtmsource_msgp + (*buff - old_msgp);
 	REPL_DPRINT2("New *buff = 0x%llx\n", *buff);
@@ -1000,7 +1000,7 @@ static	tr_search_state_t do_linear_search(repl_ctl_element *ctl, uint4 lo_addr,
 					srch_status->seqno = rec_jnl_seqno;
 				}
 				if (ctl->max_seqno < rec_jnl_seqno)
-					CTL_SET_MAX_SEQNO(ctl, rec_jnl_seqno, b->recaddr, b->recaddr, DO_EOF_ADDR_CHECK);
+					CTL_SET_MAX_SEQNO(ctl, rec_jnl_seqno, b->recaddr, b->recaddr, SKIP_EOF_ADDR_CHECK);
 				QWASSIGN(ctl->seqno, rec_jnl_seqno);
 				ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
 				if (QWEQ(rec_jnl_seqno, read_seqno))
@@ -1386,11 +1386,14 @@ static	int read_and_merge(unsigned char *buff, int maxbufflen, seq_num read_jnl_
 					} else
 						repl_log(gtmsource_log_fp, FALSE, TRUE, "\n");
 				}
-				if (TREF(gtm_environment_init)
-					DEBUG_ONLY(&& (WBTEST_CLOSE_JNLFILE != gtm_white_box_test_case_number)))
-						gtm_fork_n_core();
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SEQNUMSEARCHTIMEOUT, 2,
-					&read_jnl_seqno, &read_jnl_seqno);
+				if (!jnlpool.gtmsource_local->jnlfileonly)
+				{
+					if (TREF(gtm_environment_init)
+						DEBUG_ONLY(&& (WBTEST_CLOSE_JNLFILE != gtm_white_box_test_case_number)))
+							gtm_fork_n_core();
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SEQNUMSEARCHTIMEOUT, 2,
+						&read_jnl_seqno, &read_jnl_seqno);
+				}
 			    }
 			}
 		}
@@ -1818,7 +1821,7 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool
 			maxbufflen = gtmsource_msgbufsiz - REPL_MSG_HDRLEN;
 		}
 	} while (TRUE);
-	if (file2pool)
+	if (file2pool && !gtmsource_local->jnlfileonly)
 	{
 		gtmsource_local->read = (uint4)(read_addr % jnlpool_size) ;
 		gtmsource_local->read_state = read_state = READ_POOL;
diff --git a/sr_unix/gtmsrc.csh b/sr_unix/gtmsrc.csh
index ab571d2..af170ec 100644
--- a/sr_unix/gtmsrc.csh
+++ b/sr_unix/gtmsrc.csh
@@ -1,6 +1,6 @@
 #################################################################
 #								#
-#	Copyright 2001 Sanchez Computer Associates, Inc.	#
+#	Copyright 2001, 2014 Fidelity Information Services, Inc	#
 #								#
 #	This source code contains the intellectual property	#
 #	of its copyright holder(s), and is made available	#
@@ -83,7 +83,7 @@ if ( $?gtmsrc_last_exe == "1" ) then
 	set	path =			`echo $path        | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
 
 	# (Note: the use of an intermediate gtmroutines shell variable is necessary for csh; tcsh doesn't require it.)
-	set	gtmsrc_gtmroutines =	`echo $gtmroutines | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
+	set	gtmsrc_gtmroutines =	`echo "$gtmroutines" | sed -e "s|$gtmsrc_last_exe|$gtm_exe|"`
 	setenv	gtmroutines		"$gtmsrc_gtmroutines"
 endif
 setenv gtmsrc_last_exe	$gtm_exe
diff --git a/sr_unix/gv_trigger.c b/sr_unix/gv_trigger.c
index ea58a16..031e76c 100644
--- a/sr_unix/gv_trigger.c
+++ b/sr_unix/gv_trigger.c
@@ -88,6 +88,7 @@ error_def(ERR_DBROLLEDBACK);
 error_def(ERR_GVKILLFAIL);
 error_def(ERR_GVPUTFAIL);
 error_def(ERR_GVZTRIGFAIL);
+error_def(ERR_NEEDTRIGUPGRD);
 error_def(ERR_INDRMAXLEN);
 error_def(ERR_PATMAXLEN);
 error_def(ERR_TEXT);
@@ -100,20 +101,15 @@ error_def(ERR_TRIGSUBSCRANGE);
 LITREF	char	ctypetab[NUM_CHARS];
 LITREF	int4	gvtr_cmd_mask[GVTR_CMDTYPES];
 LITREF	mval	gvtr_cmd_mval[GVTR_CMDTYPES];
-LITREF	mval	literal_cmd;
-LITREF	mval	literal_delim;
-LITREF	mval	literal_gvsubs;
+LITREF	mval	literal_zero;
 LITREF	mval	literal_hashcount;
 LITREF	mval	literal_hashcycle;
 LITREF	mval	literal_hashlabel;
-LITREF	mval	literal_hasht;
-LITREF	mval	literal_options;
-LITREF	mval	literal_pieces;
-LITREF	mval	literal_xecute;
-LITREF	mval	literal_trigname;
-LITREF	mval	literal_chset;
-LITREF	mval	literal_zdelim;
-LITREF	mval	literal_zero;
+LITREF	mval	literal_null;
+
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	LITREF mval LITMVALNAME;
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
 
 #define	GVTR_PARSE_POINT	1
 #define	GVTR_PARSE_LEFT		2
@@ -248,7 +244,7 @@ LITREF	mval	literal_zero;
 }
 
 /* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
-#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA)				\
+#define GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA)				\
 {												\
 	if (CDB_STAGNATE > t_tries)								\
 	{											\
@@ -370,8 +366,8 @@ STATICFNDEF void gvtr_db_tpwrap_helper(sgmnt_addrs *csa, int err_code, boolean_t
 	REVERT;
 }
 
-/* Helper function used by "gvtr_db_read_hasht" function */
-STATICFNDEF boolean_t	gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
+/* Helper function used by "gvtr_db_read_hasht" and "trigger_upgrade" functions */
+boolean_t	gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
 {
 	uint4		curend;
 	boolean_t	was_null = FALSE, is_null = FALSE, is_defined;
@@ -390,26 +386,6 @@ STATICFNDEF boolean_t	gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval)
 	return is_defined;
 }
 
-STATICFNDEF boolean_t	gvtr_get_hasht_gblsubs_and_index(mval *subs_mval, mval *index, mval *ret_mval)
-{
-	uint4		curend;
-	boolean_t	was_null = FALSE, is_null = FALSE, is_defined;
-	DCL_THREADGBL_ACCESS;
-
-	SETUP_THREADGBL_ACCESS;
-	is_defined = FALSE;
-	curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
-	assert(KEY_DELIMITER == gv_currkey->base[curend]);
-	assert(gv_target->gd_csa == cs_addrs);
-	COPY_SUBS_TO_GVCURRKEY(subs_mval, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
-	COPY_SUBS_TO_GVCURRKEY(index, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
-	is_defined = gvcst_get(ret_mval);
-	assert(!is_defined || (MV_STR & ret_mval->mvtype));	/* assert that gvcst_get() sets type of mval to MV_STR */
-	gv_currkey->end = curend;	/* reset gv_currkey->end to what it was at function entry */
-	gv_currkey->base[curend] = KEY_DELIMITER;    /* restore terminator for entire key so key is well-formed */
-	return is_defined;
-}
-
 STATICFNDEF uint4	gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int type, char *start, char *end)
 {
 	mval		tmpmval;
@@ -668,8 +644,16 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 	{	/* ^#t global does not exist. Return right away. */
 		DBGTRIGR((stderr, "gvtr_db_read_hasht: no triggers\n"));
 		GVTR_HASHTGBL_READ_CLEANUP(TRUE);
+		csa->hdr->hasht_upgrade_needed = FALSE;	/* Reset now that we know there is no ^#t global in this db.
+							 * Note: It is safe to do so even if we dont hold crit.
+							 */
 		return;
 	}
+	if (csa->hdr->hasht_upgrade_needed)
+	{	/* ^#t needs to be upgraded first before reading it. Cannot proceed. */
+		GVTR_HASHTGBL_READ_CLEANUP(TRUE);
+		rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
+	}
 	/* ^#t global exists.
 	 * Initialize gv_target->gvt_trigger from ^#t(<gbl>,...) where <gbl> is the global corresponding to save_gvtarget.
 	 *
@@ -683,7 +667,7 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 	 *
 	 *	^#t global structure created by MUPIP TRIGGER
 	 *	----------------------------------------------
-	 *	^#t("GBL","#LABEL")="1"                     # Format of the ^#t global for GBL. Currently set to 1.
+	 *	^#t("GBL","#LABEL")="3"                     # Format of the ^#t global for GBL. Currently set to 3.
 	 *						    # Will get bumped up in the future when the ^#t global format changes.
 	 *	^#t("GBL","#CYCLE")=<32-bit-decimal-number> # incremented every time any trigger changes happen in ^GBL global
 	 *	^#t("GBL","#COUNT")=1                       # indicating there is 1 trigger currently defined for ^GBL global
@@ -701,7 +685,7 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 	 *          Read ^#t("GBL","#LABEL")
 	 * -----------------------------------------------------------------------------
 	 */
-	/* Check value of ^#t("GBL","#LABEL"). We expect it to be 1 indicating the format of the ^#t global.
+	/* Check value of ^#t("GBL","#LABEL"). We expect it to indicate the current format of the ^#t global.
 	 * If not, it is an integ error in the ^#t global so issue an appropriate error.
 	 */
 	gvt = save_gvtarget;	/* use smaller variable name as it is going to be used in lots of places below */
@@ -803,7 +787,7 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 		/* Read in ^#t("GBL",1,"TRIGNAME")="GBL#1" */
 		is_defined =  gvtr_get_hasht_gblsubs((mval *)&literal_trigname, ret_mval);
 		if (!is_defined)
-			HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"TRIGNAME\"", csa);
+			GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"TRIGNAME\"", csa);
 		trigdsc->rtn_desc.rt_name = ret_mval->str;	/* Copy trigger name mident */
 		trigdsc->gvt_trigger = gvt_trigger;		/* Save ptr to our main gvt_trigger struct for this trigger. With
 								 * this and given a gv_trigger_t, we can get to the gvt_trigger_t
@@ -821,7 +805,7 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 		/* Read in ^#t("GBL",1,"CMD")="S,K,ZK,ZTK,ZTR" */
 		is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_cmd, ret_mval);
 		if (!is_defined)
-			HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa);
+			GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa);
 		/* Initialize trigdsc->cmdmask */
 		ptr = ret_mval->str.addr;
 		ptr_top = ptr + ret_mval->str.len;
@@ -1035,14 +1019,13 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 			{
 				assert(!delim_defined); /* DELIM and ZDELIM should NOT have been specified at same time */
 				trigdsc->is_zdelim = TRUE;
-				/* Initialize trigdsc->delimiter */
-				trigdsc->delimiter = ret_mval->str;
 			}
 		}
 		if (delim_defined || zdelim_defined)	/* order of || is important since latter is set only if former is FALSE */
 		{
-			trigdsc->delimiter = ret_mval->str;
-			GVTR_POOL2BUDDYLIST(gvt_trigger, &trigdsc->delimiter);
+			/* Initialize trigdsc->delimiter */
+			trigdsc->delimiter = *ret_mval;
+			GVTR_POOL2BUDDYLIST(gvt_trigger, &trigdsc->delimiter.str);
 		}
 		/* Read in ^#t("GBL",1,"PIECES")="2:6;8"	*/
 		is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_pieces, ret_mval);
@@ -1084,7 +1067,7 @@ void	gvtr_db_read_hasht(sgmnt_addrs *csa)
 		/* Read in ^#t("GBL",1,"CHSET")="UTF-8". If CHSET does not match gtm_chset issue error. */
 		is_defined =  gvtr_get_hasht_gblsubs((mval *)&literal_chset, ret_mval);
 		if (!is_defined)
-			HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CHSET\"", csa);
+			GVTR_HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CHSET\"", csa);
 		if ((!gtm_utf8_mode && ((STR_LIT_LEN(CHSET_M_STR) != ret_mval->str.len)
 						|| memcmp(ret_mval->str.addr, CHSET_M_STR, STR_LIT_LEN(CHSET_M_STR))))
 			|| (gtm_utf8_mode && ((STR_LIT_LEN(CHSET_UTF8_STR) != ret_mval->str.len)
@@ -1331,7 +1314,6 @@ void	gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
 {
 	sgmnt_addrs		*csa;
 	sgmnt_data_ptr_t	csd;
-	gv_namehead		*dir_tree;
 	uint4			lcl_t_tries, save_t_tries, loopcnt;
 	uint4			cycle_start;
 	boolean_t		root_srch_needed;
@@ -1345,9 +1327,16 @@ void	gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
 	save_t_tries = t_tries; /* note down the value of t_tries at the entry to this function */
 	csa = gvt->gd_csa;
 	assert(NULL != csa);	/* database for this gvt better be opened at this point */
-	dir_tree = csa->dir_tree;
-	if (gvt == dir_tree)
-		return; /* trigger initialization should return for directory tree (e.g. set^%GBLDEF is caller) */
+	/* The directory tree corresponds to a non-existent global which does not have any triggers so in this case
+	 * return right away. No trigger initialization needed.
+	 */
+	if (gvt == csa->dir_tree)
+		return;
+	/* We know there are no triggers for the ^#t global so return right away in that case too.
+	 * In fact it is necessary to do this if "trigger_upgrade" is caller as we dont want a NEEDTRIGUPGRD error there.
+	 */
+	if (gvt == csa->hasht_tree)
+		return;
 	csd = csa->hdr;
 	assert((gvt->db_trigger_cycle != cycle) || (gvt->db_dztrigger_cycle < csa->db_dztrigger_cycle));
 	root_srch_needed = FALSE;
@@ -1580,7 +1569,7 @@ int	gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_
 	     (NULL != trigdsc) && (trigdsc != trigstop);
 	     --trigmax, trigdsc = *(gv_trigger_t **)((char *)trigdsc + trig_list_offset))	/* Follow the designated list */
 	{
-		DBGTRIGR((stderr, "gvtr_match_n_invoke: top of trigr scan loop\n"));
+		DBGTRIGR((stderr, "gvtr_match_n_invoke: top of trigr scan loop (%d)\n", trigmax));
 		trigstop = trigstart;		/* Stop when we get back to where we started */
 		assertpro(0 <= trigmax);		/* Loop ender "just in case" */
 		assert(trigdsc >= gvt_trigger->gv_trig_array);
@@ -1623,13 +1612,15 @@ int	gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_
 			 * If so, check if any of those pieces are different. If not, trigger should NOT be invoked.
 			 */
 			ok_to_invoke_trigger = TRUE;
+			trigparms->ztdelim_new = (mval *)&literal_null;
 			if (is_set_trigger)
 			{
 				assert(0 == ztupd_mval->mvtype);
-				if (trigdsc->delimiter.len)
+				if (trigdsc->delimiter.str.len)
 				{
+					trigparms->ztdelim_new = (mval *)&trigdsc->delimiter;
 					strpiecediff(&trigparms->ztoldval_new->str, &trigparms->ztvalue_new->str,
-						&trigdsc->delimiter, trigdsc->numpieces, trigdsc->piecearray,
+						&trigdsc->delimiter.str, trigdsc->numpieces, trigdsc->piecearray,
 						!trigdsc->is_zdelim && gtm_utf8_mode, ztupd_mstr);
 					if (!ztupd_mstr->len)
 					{	/* No pieces of interest changed. So dont invoke trigger. */
diff --git a/sr_unix/gv_trigger.h b/sr_unix/gv_trigger.h
index 74c30be..527f8fe 100644
--- a/sr_unix/gv_trigger.h
+++ b/sr_unix/gv_trigger.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -128,7 +128,7 @@ typedef struct gv_trigger_struct
 					 *	piecearray[1].min=8, piecearray[1].max=8 */
 	rtn_tabent	rtn_desc;	/* Compiled routine name/objcode; Inited by gvtr_db_read_hasht() */
 	boolean_t	is_zdelim;	/* TRUE if "ZDELIM" was specified; FALSE if "DELIM" was specified */
-	mstr		delimiter;	/* is a copy of ^#t(<GBL>,<index>,"DELIM") or ^#t(..."ZDELIM") whichever is defined */
+	mval		delimiter;	/* is a copy of ^#t(<GBL>,<index>,"DELIM") or ^#t(..."ZDELIM") whichever is defined */
 	mstr		options;	/* is a copy of ^#t(<GBL>,<index>,"OPTIONS") */
 	mval		xecute_str;	/* Trigger code to execute */
 	struct gvt_trigger_struct	/* top of gvt_trigger block this trigger belongs to. Used in src lookup when we know */
@@ -201,11 +201,21 @@ typedef struct gvtr_invoke_parms_struct
 	ztrig_cycle_mismatch = (CSA->db_dztrigger_cycle && (GVT->db_dztrigger_cycle != CSA->db_dztrigger_cycle));		\
 	db_trigger_cycle_mismatch = (GVT->db_trigger_cycle != cycle);								\
 	cycle_mismatch = (db_trigger_cycle_mismatch || ztrig_cycle_mismatch);							\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: CSA->db_ztrigger_cycle=%d\n", cycle));				\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->db_trigger_cycle=%d\n", GVT->db_trigger_cycle));		\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: CSA->db_dztrigger_cycle=%d\n", CSA->db_dztrigger_cycle));		\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->db_dztrigger_cycle=%d\n", GVT->db_dztrigger_cycle));		\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: local_tn=%d\n", local_tn));						\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: GVT->trig_local_tn=%d\n", GVT->trig_local_tn));			\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: ztrig_cycle_mismatch=%d\n", ztrig_cycle_mismatch));			\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: db_trigger_cycle_mismatch=%d\n", db_trigger_cycle_mismatch));	\
+	DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: cycle_mismatch=%d t_tries=%d\n", cycle_mismatch, t_tries));		\
 	/* Set up wrapper even if no triggers if this is for ZTRIGGER command */						\
 	if (cycle_mismatch || (NULL != GVT->gvt_trigger) || (ERR_GVZTRIGFAIL == T_ERR))						\
 	{	/* Create TP wrap if needed */											\
 		if (!dollar_tlevel)												\
 		{	/* need to create implicit TP wrap */									\
+			DBGTRIGR((stderr, "GVTR_INIT_AND_TPWRAP_IF_NEEDED: creating TP wrapper\n"));				\
 			DEBUG_ONLY(was_nontp = TRUE;)										\
 			assert(!LCL_TSTART);											\
 			/* Set a debug-only global variable to indicate that from now onwards, until the completion of this	\
@@ -415,8 +425,8 @@ typedef struct gvtr_invoke_parms_struct
 	hasht_tree = CSA->hasht_tree;								\
 	if (NULL == hasht_tree)									\
 	{	/* Allocate gv_target like structure for "^#t" global in this database file */	\
-		gvname.var_name.addr = literal_hasht.str.addr;					\
-		gvname.var_name.len = literal_hasht.str.len;					\
+		gvname.var_name.addr = HASHT_GBLNAME;						\
+		gvname.var_name.len = HASHT_GBLNAME_LEN;					\
 		gvname.marked = FALSE;								\
 		COMPUTE_HASH_MNAME(&gvname);							\
 		hasht_tree = targ_alloc(CSA->hdr->max_key_size, &gvname, NULL);			\
@@ -430,6 +440,10 @@ typedef struct gvtr_invoke_parms_struct
 {															\
 	unsigned char		*key;											\
 															\
+	GBLREF	gv_key			*gv_currkey;									\
+	GBLREF	gd_region		*gv_cur_region;									\
+	GBLREF	sgmnt_data_ptr_t	cs_data;									\
+															\
 	key = &gv_currkey->base[0];											\
 	memcpy(key, HASHT_GBLNAME, HASHT_GBLNAME_FULL_LEN);	/* including terminating '\0' subscript */		\
 	key += HASHT_GBLNAME_FULL_LEN;											\
@@ -445,23 +459,28 @@ typedef struct gvtr_invoke_parms_struct
 	GVCST_ROOT_SEARCH;												\
 }
 
-#define	SWITCH_TO_DEFAULT_REGION			\
-{							\
-	GBLREF	uint4		dollar_tlevel;		\
-	GBLREF	gd_addr		*gd_header;		\
-	GBLREF	gv_namehead	*gv_target;		\
-							\
-	gd_region		*default_region;	\
-							\
-	assert(NULL != gd_header);			\
-	default_region = gd_header->maps->reg.addr;	\
-	if (!default_region->open)			\
-		gv_init_reg(default_region);		\
-	TP_CHANGE_REG_IF_NEEDED(default_region);	\
-	SET_GVTARGET_TO_HASHT_GBL(cs_addrs);		\
-	assert(NULL != gv_target);			\
-	if (dollar_tlevel)				\
-		tp_set_sgm();				\
+/* Caller has to check for "NULL" value of "cs_addrs" and act accordingly */
+#define	GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg)							\
+{													\
+	GBLREF	uint4		dollar_tlevel;								\
+	GBLREF	gv_namehead	*gv_target;								\
+	GBLREF	gd_region	*gv_cur_region;								\
+	GBLREF	gv_key		*gv_currkey;								\
+													\
+	if (!reg->open)											\
+		gv_init_reg(reg);									\
+	gv_cur_region = reg;										\
+	change_reg(); /* TP_CHANGE_REG wont work as we need to set sgm_info_ptr */			\
+	if (NULL != cs_addrs)										\
+	{												\
+		SET_GVTARGET_TO_HASHT_GBL(cs_addrs);	/* sets up gv_target */				\
+		assert(NULL != gv_target);								\
+		INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;	/* sets up gv_currkey */			\
+	} else												\
+	{												\
+		DEBUG_ONLY(gv_target = NULL;)	/* to keep cs_addrs/gv_target in sync */		\
+		DEBUG_ONLY(gv_currkey->base[0] = '\0';)	/* to keep gv_target/gv_currkey in sync */	\
+	}												\
 }
 
 GBLREF	uint4		dollar_tlevel;
@@ -624,4 +643,19 @@ GBLREF	int4		tstart_trigger_depth;
 	assert(MAX_TRIG_UTIL_LEN >= UTIL_LEN);						\
 }
 
+/* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
+#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA)				\
+{												\
+	if (CDB_STAGNATE > t_tries)								\
+		t_retry(cdb_sc_triggermod);							\
+	else											\
+	{											\
+		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);		\
+		/* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */	\
+		SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT);			\
+		rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,	\
+			trigvn_len, trigvn, util_len, util_buff);				\
+	}											\
+}
+
 #endif
diff --git a/sr_unix/gv_trigger_protos.h b/sr_unix/gv_trigger_protos.h
index 8a1d8e2..5c22775 100644
--- a/sr_unix/gv_trigger_protos.h
+++ b/sr_unix/gv_trigger_protos.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -13,8 +13,6 @@
 #define GV_TRIGGER_PROTOS_H_INCLUDED
 
 STATICFNDCL	void		gvtr_db_tpwrap_helper(sgmnt_addrs *csa, int err_code, boolean_t root_srch_needed);
-STATICFNDCL	boolean_t	gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval);
-STATICFNDCL	boolean_t	gvtr_get_hasht_gblsubs_and_index(mval *subs_mval, mval *index, mval *ret_mval);
 STATICFNDCL	uint4		gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int type, char *start, char *end);
 STATICFNDCL	uint4		gvtr_process_pattern(char *ptr, uint4 len, gvtr_subs_t *subsdsc, gvt_trigger_t *gvt_trigger);
 STATICFNDCL	uint4		gvtr_process_gvsubs(char *start, char *end, gvtr_subs_t *subsdsc,
@@ -22,8 +20,9 @@ STATICFNDCL	uint4		gvtr_process_gvsubs(char *start, char *end, gvtr_subs_t *subs
 STATICFNDCL	boolean_t	gvtr_is_key_a_match(char *keysub_start[], gv_trigger_t *trigdsc, mval *lvvalarray[]);
 STATICFNDCL	boolean_t	gvtr_is_value_a_match(mval *val, gv_trigger_t *trigdsc);
 
-void	gvtr_db_read_hasht(sgmnt_addrs *csa);
-void	gvtr_free(gv_namehead *gvt);
-void	gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_code);
-int	gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_parms);
+boolean_t	gvtr_get_hasht_gblsubs(mval *subs_mval, mval *ret_mval);
+void		gvtr_db_read_hasht(sgmnt_addrs *csa);
+void		gvtr_free(gv_namehead *gvt);
+void		gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_code);
+int		gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_parms);
 #endif
diff --git a/sr_unix/gvcst_init_sysops.c b/sr_unix/gvcst_init_sysops.c
index 8aea912..f49d8db 100644
--- a/sr_unix/gvcst_init_sysops.c
+++ b/sr_unix/gvcst_init_sysops.c
@@ -28,9 +28,7 @@
 #include "gtm_string.h"
 #include "gtm_sem.h"
 #include "gtm_statvfs.h"
-#ifdef __linux__
-#include "hugetlbfs_overrides.h"
-#endif
+#include "hugetlbfs_overrides.h"	/* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
 
 #include "gt_timer.h"
 #include "gdsroot.h"
@@ -356,7 +354,7 @@ gd_region *dbfilopn (gd_region *reg)
 			free(seg->file_cntl);
 			seg->file_cntl = 0;
 		}
-		RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
 	}
 	assert(((int)pblk.b_esl + 1) <= SIZEOF(seg->fname));
 	memcpy(seg->fname, pblk.buffer, pblk.b_esl);
@@ -395,7 +393,7 @@ gd_region *dbfilopn (gd_region *reg)
 				free(seg->file_cntl);
 				seg->file_cntl = 0;
 			}
-			RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
 		}
 		reg->read_only = TRUE;			/* maintain csa->read_write simultaneously */
 		csa->read_write = FALSE;	/* maintain reg->read_only simultaneously */
@@ -408,7 +406,7 @@ gd_region *dbfilopn (gd_region *reg)
         if (-1 == stat_res)
         {
         	save_errno = errno;
-        	RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
+        	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
         }
 	set_gdid_from_stat(&udi->fileid, &buf);
 	if (prev_reg = gv_match(reg))
@@ -446,11 +444,7 @@ void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size)
 		assertpro(dba_bg == reg->dyn.addr->acc_meth);
 		tmp_sec_size += CACHE_CONTROL_SIZE(csd) + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE);
 	}
-#	ifdef HUGETLB_SUPPORTED
-	*sec_size = ROUND_UP(tmp_sec_size, OS_HUGEPAGE_SIZE);
-#	else
-	*sec_size = ROUND_UP(tmp_sec_size, OS_PAGE_SIZE);
-#	endif
+	ADJUST_SHM_SIZE_FOR_HUGEPAGES(tmp_sec_size, *sec_size);	/* *sec_size is adjusted size */
 	return;
 }
 
@@ -1158,7 +1152,7 @@ int db_init(gd_region *reg)
 			if (-1 == shmctl(csa->nl->jnlpool_shmid, IPC_STAT, &shmstat))
 			{
 				save_errno = errno;
-				if ((EINVAL == save_errno) || (EIDRM == save_errno)) /* EIDRM is only on Linux */
+				if (SHM_REMOVED(save_errno))
 				{
 					replinst_mismatch = FALSE;
 					csa->nl->jnlpool_shmid = jnlpool.repl_inst_filehdr->jnlpool_shmid;
diff --git a/sr_unix/hugetlbfs_overrides.h b/sr_unix/hugetlbfs_overrides.h
new file mode 100644
index 0000000..b4a2126
--- /dev/null
+++ b/sr_unix/hugetlbfs_overrides.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), 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__)
+#	if ( 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
+
+#ifdef HUGETLB_SUPPORTED
+#	define	ADJUST_SHM_SIZE_FOR_HUGEPAGES(SRCSIZE, DSTSIZE)	DSTSIZE = ROUND_UP(SRCSIZE, OS_HUGEPAGE_SIZE)
+#else
+	OS_PAGE_SIZE_DECLARE
+#	define	ADJUST_SHM_SIZE_FOR_HUGEPAGES(SRCSIZE, DSTSIZE)	DSTSIZE = ROUND_UP(SRCSIZE, OS_PAGE_SIZE)
+#endif
+
+#endif /* HUGETLBFS_OVERRIDES_H_ */
diff --git a/sr_unix/incr_link.c b/sr_unix/incr_link.c
index f20e4ee..d33a815 100644
--- a/sr_unix/incr_link.c
+++ b/sr_unix/incr_link.c
@@ -12,7 +12,6 @@
 #include "mdef.h"
 
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <sys/shm.h>
 
 #include <errno.h>
@@ -36,9 +35,12 @@
 #include "gtmdbglvl.h"
 #include "cmd_qlf.h"	/* needed for CQ_UTF8 */
 #include "gtm_text_alloc.h"
-#include "zhist.h"
 #include "send_msg.h"
 #include "cacheflush.h"
+#include "rtnobj.h"
+#include "zbreak.h"
+#include "interlock.h"
+#include "util.h"
 
 /* Define linkage types */
 typedef enum
@@ -71,6 +73,7 @@ typedef enum
 	{											\
 		free(hdr);									\
 		hdr = NULL;									\
+		RELEASE_RECENT_ZHIST;								\
 		return IL_RECOMPILE;	/* Signal recompile */					\
 	}											\
 }
@@ -115,40 +118,63 @@ error_def(ERR_DLLCHSETUTF8);
 error_def(ERR_DLLVERSION);
 error_def(ERR_INVOBJFILE);
 error_def(ERR_LOADRUNNING);
-error_def(ERR_TEXT);
+error_def(ERR_RLNKRECLATCH);
 error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+error_def(ERR_ZLINKBYPASS);
 error_def(ERR_ZLINKFILE);
 
 STATICFNDCL void	res_free(res_list *root);
 STATICFNDCL boolean_t	addr_fix(int file, unsigned char *shdr, linktype linktyp, urx_rtnref *urx_lcl);
-STATICFNDCL void	zl_error(linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2);
-STATICFNDCL void	zl_error_hskpng(linktype linktyp, int4 file);
+STATICFNDCL void	zl_error(void *recent_zhist, linktype linktyp, int4 file, int4 err, int4 len, char *addr,
+				 int4 len2, char *addr2);
+STATICFNDCL void	zl_error_hskpng(linktype linktyp, int4 file, void *recent_zhist);
 
 /* incr_link - read and process a mumps object module.  Link said module to currently executing image */
-boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname)
+#ifdef AUTORELINK_SUPPORTED
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, zro_hist *recent_zhist, uint4 fname_len, char *fname)
+#else
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname)
+#endif
 {
-	rhdtyp		*old_rhead;
-	int		sect_ro_rel_size, sect_rw_rel_size, name_buf_len, alloc_len, order, rc, save_errno;
-	uint4		lcl_compiler_qlf;
-	boolean_t	dynlits;
-	ssize_t	 	status, sect_rw_nonrel_size, sect_ro_rel_offset;
-	size_t		offset_correction;
-	lab_tabent	*lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top;
-	mident_fixed	module_name;
-	pre_v5_mident	*pre_v5_routine_name;
-	urx_rtnref	urx_lcl_anchor;
-	unsigned char	*shdr, *rel_base, *newaddr;
-	mval		*curlit, *littop;
-	lab_tabent	*curlbe, *lbetop;
-	var_tabent	*curvar, *vartop;
-	char		name_buf[PATH_MAX + 1], marker[SIZEOF(JSB_MARKER) - 1], *rw_rel_start;
-	linktype	linktyp;
-	struct stat	obj_stat;
-	ZOS_ONLY(ESD	symbol;)
+	rhdtyp			*old_rhead;
+	rtn_tabent		*tabent_ptr;
+	int			sect_ro_rel_size, sect_rw_rel_size, name_buf_len, alloc_len, order;
+	uint4			lcl_compiler_qlf;
+	boolean_t		dynlits;
+	ssize_t	 		status, sect_rw_nonrel_size, sect_ro_rel_offset;
+	size_t			offset_correction, rtnname_off;
+	lab_tabent		*lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top;
+	mident_fixed		module_name;
+	pre_v5_mident		*pre_v5_routine_name;
+	urx_rtnref		urx_lcl_anchor;
+	unsigned char		*shdr, *rel_base, *newaddr;
+	mstr			rtnname;
+	mval			*curlit, *littop;
+	lab_tabent		*curlbe, *lbetop;
+	var_tabent		*curvar, *vartop;
+	char			name_buf[PATH_MAX + 1], marker[SIZEOF(JSB_MARKER) - 1], *rw_rel_start;
+	char			rtnname_buf[MAX_MIDENT_LEN];
+	linktype		linktyp;
+	va_list			save_last_va_list_ptr;
+	boolean_t		util_copy_saved;
+	char			*save_util_outptr;
+	int4			save_error_condition;
+	ZOS_ONLY(ESD		symbol;)
 #	ifdef _AIX
-	FILHDR          hddr;
-	unsigned short  magic;
+	FILHDR          	hddr;
+	unsigned short  	magic;
 #	endif
+#	ifdef AUTORELINK_SUPPORTED
+	relinkrec_t		*rec;
+	zro_validation_entry	*zhent;
+	open_relinkctl_sgm	*linkctl;
+#	ifdef DEBUG
+	relinkrec_t		*relinkrec;
+	int			rtnlen;
+	char			save_char, *rtnname2;
+#	endif /* DEBUG */
+#	endif /* AUTORELINK_SUPPORTED */
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -161,9 +187,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	ZOS_FREE_TEXT_SECTION;
 #	endif
 	urx_lcl_anchor.len = 0;
-	urx_lcl_anchor.addr = 0;
+	urx_lcl_anchor.addr = NULL;
 	urx_lcl_anchor.lab = 0;
-	urx_lcl_anchor.next = 0;
+	urx_lcl_anchor.next = NULL;
 	assert(NULL == hdr);
 	assert(NULL == sect_ro_rel);
 	assert(NULL == sect_rw_rel);
@@ -172,18 +198,53 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	shdr = NULL;
 	sect_ro_rel = sect_rw_rel = sect_rw_nonrel = NULL;
 	if (file_desc)
-	{	/* This is a disk resident object we mmap and share if autorelink is enabled in that directory, or instead we
+	{	/* This is a disk resident object we share if autorelink is enabled in that directory, or instead we
 		 * read/link into process private storage if autorelink is not enabled.
 		 */
 		if ((NULL == zro_entry) || (NULL == zro_entry->relinkctl_sgmaddr))
+		{
 			linktyp = LINK_PPRIVOBJ;
-		else
+			/* No history if process private link */
+			ARLINK_ONLY(assert(NULL == recent_zhist));
+		} else
+		{
 			linktyp =  LINK_SHROBJ;
+#			if defined(AUTORELINK_SUPPORTED) && defined(DEBUG)
+			/* Need a history if sharing the object */
+			assert(NULL != recent_zhist);
+			/* Later call to rtnobj_shm_malloc will use recent_zhist->end - 1 as the zro_validation_entry
+			 * to get at the linkctl and relinkrec so assert that it is indeed linkctl corresponding to zro_entry.
+			 */
+			assert((recent_zhist->end - 1)->relinkctl_bkptr
+			       == (open_relinkctl_sgm *)zro_entry->relinkctl_sgmaddr);
+			relinkrec = (recent_zhist->end - 1)->relinkrec;
+			rtnlen = STRLEN(relinkrec->rtnname_fixed.c);
+			assert(fname_len >= (STR_LIT_LEN(DOTOBJ) + rtnlen));
+			rtnname2 = fname + fname_len - 1;
+			while (rtnname2 >= fname)
+			{
+				if ('/' == *rtnname2)
+				{
+					rtnname2++;
+					break;
+				}
+				rtnname2--;
+			}
+			save_char = *rtnname2;
+			if ('_' == save_char)
+				*rtnname2 = '%'; /* Temporary adjustment for below assert to not fail */
+			assert(!memcmp(relinkrec->rtnname_fixed.c, rtnname2, rtnlen));
+			if ('_' == save_char)
+				*rtnname2 = save_char;	/* restore */
+#			endif	/* AUTORELINK_SUPPORTED && DEBUG */
+		}
 		NON_USHBIN_ONLY(assert(LINK_PPRIVOBJ == linktyp));	/* No autorelink in non-ushbin platform */
 	} else
-	{	/* With no file descriptor, this can only be linkage from a shared library */
+	{
+		/* With no file descriptor, this can only be linkage from a shared library and shared libraries have no history */
+		ARLINK_ONLY(assert(NULL == recent_zhist));
+		assert(NULL != zro_entry);
 		linktyp = LINK_SHRLIB;
-		NON_USHBIN_ONLY(assert(FALSE /* Shared libraries not supported on this platform */));
 	}
 	/* Get the routine header where we can make use of it */
 	hdr = (rhdtyp *)malloc(SIZEOF(rhdtyp));
@@ -200,35 +261,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			memcpy(hdr, shdr, SIZEOF(rhdtyp));
 			hdr->shlib_handle = zro_entry->shrlib;
 			break;
-		case LINK_SHROBJ:
-			FSTAT_FILE(file_desc, &obj_stat, rc);
-			if (-1 == rc)
-			{	/* Need to not use zl_error() here since need compound error to put out errno */
-				save_errno = errno;
-				ZOS_FREE_TEXT_SECTION;
-				zl_error_hskpng(linktyp, file_desc);
-				rts_error_csa(NULL, VARLSTCNT(5) ERR_ZLINKFILE, 2, fname_len, fname, save_errno);
-			}
-			/* Share the object file (in its entirety) via mmap() */
-			shdr = (unsigned char *)mmap(NULL, obj_stat.st_size, PROT_EXEC|PROT_READ, MAP_SHARED, file_desc, 0)
-				+ NATIVE_HDR_LEN;		/* shdr->routinehdr (past native object header) */
-			if (MAP_FAILED == (void *)shdr)
-			{	/* If mmap() fails, send error to both process and to syslog. Note we do not use zlerror()
-				 * here since need to send a compound message about the failure.
-				 */
-				save_errno = errno;
-				send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_ZLINKFILE, 2, fname_len, fname, ERR_SYSCALL,
-					     5, LEN_AND_LIT("mmap"), CALLFROM, save_errno);
-				ZOS_FREE_TEXT_SECTION;
-				zl_error_hskpng(linktyp, file_desc);
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_ZLINKFILE, 2, fname_len, fname, ERR_SYSCALL,
-					      5, LEN_AND_LIT("mmap"), CALLFROM, save_errno);
-			}
-			memcpy(hdr, shdr, SIZEOF(rhdtyp));
-			hdr->shared_len = obj_stat.st_size;	/* Record length we shared so we can unmap it when done */
-			break;
 #		endif
 		case LINK_PPRIVOBJ:
+		case LINK_SHROBJ:
 			/* Seek past native object headers to get GT.M object's routine header */
 			/* To check if it is not an xcoff64 bit .o */
 #			ifdef _AIX
@@ -239,11 +274,11 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 				if (magic != U64_TOCMAGIC)
 				{
 					ZOS_FREE_TEXT_SECTION;
-					zl_error_hskpng(linktyp, file_desc);
+					zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
 					return IL_RECOMPILE;
 				}
 			} else
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 #			endif
 			/* In the GOFF .o on zOS, if the symbol name(name of the module) exceeds ESD_NAME_MAX_LENGTH (8),
 			 * then 2 extra extended records are emitted, which causes the start of text section to vary
@@ -252,20 +287,20 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			DOREADRC(file_desc, &symbol, SIZEOF(symbol), status);	/* This is HDR record */
 			if (0 == status)
 			{
-				DOREADRC(file_desc, &symbol, SIZEOF(symbol), status)	/* First symbol (ESD record) */
-					if (0 == status)
+				DOREADRC(file_desc, &symbol, SIZEOF(symbol), status);	/* First symbol (ESD record) */
+				if (0 == status)
+				{
+					if (0x01 == symbol.ptv[1])	/* Means the extended records are there */
+						extended_symbols_present = TRUE;
+					else
 					{
-						if (0x01 == symbol.ptv[1])	/* Means the extended records are there */
-							extended_symbols_present = TRUE;
-						else
-						{
-							assert(0x0 == symbol.ptv[1]);
-							extended_symbols_present = FALSE;
-						}
+						assert(0x0 == symbol.ptv[1]);
+						extended_symbols_present = FALSE;
 					}
+				}
 			}
 			if (0 != status)
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 #			endif
 			if (-1 != (status = (ssize_t)lseek(file_desc, NATIVE_HDR_LEN, SEEK_SET)))
 			{
@@ -276,7 +311,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			if (0 != status)
 			{
 				CHECK_NONUSB_RECOMPILE_RETURN;
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 			}
 			break;
 		default:
@@ -290,7 +325,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		{
 			CHECK_NONUSB_RECOMPILE_RETURN;
 		}
-		zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+		zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 	}
 	/* Binary version check. If no match, shlib gets error, otherwise signal recompile */
 	if (MAGIC_COOKIE != hdr->objlabel)
@@ -305,7 +340,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 				pre_v5_routine_name = (pre_v5_mident *)((char*)hdr + PRE_V5_RTNHDR_RTNOFF);
 				for (len = 0; len < SIZEOF(pre_v5_mident) && pre_v5_routine_name->c[len]; len++)
 					;
-				zl_error(linktyp, 0, ERR_DLLVERSION, len, &(pre_v5_routine_name->c[0]),
+				zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, len, &(pre_v5_routine_name->c[0]),
 					 zro_entry->str.len, zro_entry->str.addr);
 			}
 #			if defined(__osf__) || defined(__hppa)
@@ -315,7 +350,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 				 */
 				v50v51_mstr	*mstr5051;	/* declare here so don't have to conditionally add above */
 				mstr5051 = (v50v51_mstr *)((char *)hdr + V50V51_RTNHDR_RTNMSTR_OFFSET);
-				zl_error(linktyp, 0, ERR_DLLVERSION, mstr5051->len,
+				zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, mstr5051->len,
 					 ((char *)shdr + *(int4 *)((char *)hdr + V50V51_FTNHDR_LITBASE_OFFSET)
 					  + (int4)mstr5051->addr), zro_entry->str.len, zro_entry->str.addr);
 			}
@@ -324,13 +359,13 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			{	/* Note: routine_name field has not been relocated yet, so compute its absolute
 				 * address in the shared library and use it
 				 */
-				zl_error(linktyp, 0, ERR_DLLVERSION, hdr->routine_name.len, (char *)shdr +
-					 (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+				zl_error(RECENT_ZHIST, linktyp, 0, ERR_DLLVERSION, hdr->routine_name.len,
+					(char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
 					 zro_entry->str.len, zro_entry->str.addr);
 			}
 		}
 		ZOS_FREE_TEXT_SECTION;
-		zl_error_hskpng(linktyp, file_desc);
+		zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
 		return IL_RECOMPILE;
 	}
 	if (((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) || (!(hdr->compiler_qlf & CQ_UTF8) && gtm_utf8_mode))
@@ -342,17 +377,17 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			 */
 			if ((lcl_compiler_qlf & CQ_UTF8) && !gtm_utf8_mode)
 			{
-				zl_error(linktyp, 0, ERR_DLLCHSETUTF8, (int)hdr->routine_name.len, (char *)shdr +
-					 (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+				zl_error(NULL, linktyp, 0, ERR_DLLCHSETUTF8, (int)hdr->routine_name.len,
+					(char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
 					 (int)zro_entry->str.len, zro_entry->str.addr);
 			} else
 			{
-				zl_error(linktyp, 0, ERR_DLLCHSETM, (int)hdr->routine_name.len, (char *)shdr +
-					 (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
+				zl_error(NULL, linktyp, 0, ERR_DLLCHSETM, (int)hdr->routine_name.len,
+					(char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr,
 					 (int)zro_entry->str.len, zro_entry->str.addr);
 			}
 		}
-		zl_error_hskpng(linktyp, file_desc);
+		zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
 		if ((lcl_compiler_qlf & CQ_UTF8) && !gtm_utf8_mode)
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_INVOBJFILE, 2, fname_len, fname, ERR_TEXT, 2,
 				LEN_AND_LIT("Object compiled with CHSET=UTF-8 which is different from $ZCHSET"));
@@ -360,6 +395,117 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_INVOBJFILE, 2, fname_len, fname, ERR_TEXT, 2,
 				LEN_AND_LIT("Object compiled with CHSET=M which is different from $ZCHSET"));
 	}
+	/* We need to check if this is a relink of an already linked routine. To do that, we need to be able to fetch
+	 * the routine name from the object file in question in order to look the routine up.
+	 */
+	switch(linktyp)
+	{
+		ARLINK_ONLY(case LINK_SHROBJ:);
+		case LINK_PPRIVOBJ:
+			rtnname = ((rhdtyp *)hdr)->routine_name;
+			rtnname_off = (size_t)hdr->literal_text_adr + (size_t)rtnname.addr;	/* Offset into object of rtnname */
+			ZOS_ONLY(assertpro(FALSE /* Read file pointer being reset - recode for ZOS */));
+			/* Read the routine name from the object file */
+			if (-1 != (status = (ssize_t)lseek(file_desc, rtnname_off + NATIVE_HDR_LEN, SEEK_SET)))
+			{
+				DOREADRC_OBJFILE(file_desc, rtnname_buf, rtnname.len, status);
+			} else
+				status = errno;
+			if (0 != status)
+				zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+			rtnname.addr = rtnname_buf;
+			/* Reset read file-pointer for object file back to what it was */
+			status = (ssize_t)lseek(file_desc, NATIVE_HDR_LEN + SIZEOF(rhdtyp), SEEK_SET);
+			if (-1 == status)
+				zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+			break;
+		case LINK_SHRLIB:
+			rtnname = ((rhdtyp *)shdr)->routine_name;
+			/* Routine name not yet relocated so effectively do so */
+			rtnname.addr = (char *)shdr + (size_t)((rhdtyp *)shdr)->literal_text_adr + (size_t)rtnname.addr;
+			break;
+		default:
+			assert(FALSE);
+ 	}
+	/* Now check if we know about this routine and if so, if the (new) object hash is the same as the one we currently
+	 * have linked. Note both new and old flavors of the routine must either both not be autorelink-enabled or must
+	 * both be autorelink-enabled and if autorelink-enabled, must be loaded from the same directory and thus into the same
+	 * set of shared memory structures to be able to bypass the link. This might could be eased in the future for certain
+	 * special cases.
+	 */
+	if (find_rtn_tabent(&tabent_ptr, &rtnname))
+	{
+		old_rhead = (rhdtyp *)tabent_ptr->rt_adr;
+		assert(NULL != old_rhead);
+#		ifdef AUTORELINK_SUPPORTED
+		zhent = (LINK_SHROBJ == linktyp) ? recent_zhist->end - 1 : NULL;
+		if ((old_rhead->objhash == hdr->objhash)
+		    && (((NULL == zhent) && (NULL == old_rhead->relinkctl_bkptr))			/* Both non-relink */
+			|| (NULL != zhent) && (zhent->relinkctl_bkptr == old_rhead->relinkctl_bkptr)))  /* Both same relink */
+#		else
+		if (old_rhead->objhash == ((rhdtyp *)hdr)->objhash)
+#		endif
+		{	/* This is the same routine - abort re-link but if autorelink-enabled, use the new history.
+			 * Note even a psueo-relink should cancel all the breakpoints in the module. Note we don't address
+			 * issues with whether this would have been a recursive relink or not since when we don't actually do
+			 * the relink, there's no way to remove breakpoints when the last use of this routine leaves the stack
+			 * so eliminate the breakpoints now since newly linked routines are anyway not expected to have
+			 * breakpoints.
+			 */
+			zr_remove_zbrks(old_rhead, NOBREAKMSG);
+			/* Info level message that link was bypassed. Since this could pollute the error buffer, save and
+			 * restore it across the info message we put out (it is either displayed or it isn't - no need to cache it.
+			 */
+#			ifdef ZLINK_BYPASS /* #ifdef'd out for now due to issues with ERRWETRAP */
+			SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+			save_error_condition = error_condition;
+			error_condition = 0;
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKBYPASS, 2, fname_len, fname); /* Info msg returns */
+			error_condition = save_error_condition;
+			RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+#			endif
+			/* Note do these cleanup  release/reset after the error message so these values still around if the error
+			 * causes an issue in debugging.
+			 */
+			free(hdr);		/* Don't need this (new) copy of routine header */
+			hdr = NULL;
+#			ifdef AUTORELINK_SUPPORTED
+			if (NULL != old_rhead->zhist)
+				free(old_rhead->zhist);		/* Free up previously auto-relinked structures */
+			/* Save new history if supplied or NULL */
+			old_rhead->zhist = recent_zhist;
+#			endif
+			return IL_DONE;		/* Pretend we did the link (which, effectively, we already have) */
+		}
+	}
+#	ifdef AUTORELINK_SUPPORTED
+	/* For shared object, time to pull it into shared memory */
+	if (LINK_SHROBJ == linktyp)
+	{
+		/* Currently, rtnobj_hdr_t->objLen is a 4-byte field so we cannot support object file sizes > 4Gb for now */
+		assert(4 == SIZEOF(hdr->object_len));	/* i.e. object file size is guaranteed to be < 4Gb */
+		assert(4 == SIZEOF(((rtnobj_hdr_t *)NULL)->objLen));	/* i.e. object file size is guaranteed to be < 4Gb */
+		/* Allocate buffer for routine object in shared memory. If one already exists, use it */
+		if ((size_t)MAXUINT4 <= ((size_t)hdr->object_len + OFFSETOF(rtnobj_hdr_t, userStorage)))
+		{	/* Currently, rtnobj_hdr_t->objLen is a 4-byte field so we cannot support object file
+			 * sizes > 4Gb for now.
+			 */
+			ZOS_FREE_TEXT_SECTION;
+			zl_error_hskpng(linktyp, file_desc, RECENT_ZHIST);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, fname_len, fname, ERR_TEXT, 2,
+				LEN_AND_LIT("Object file size > 4Gb cannot be auto-relinked"));
+		}
+		shdr = rtnobj_shm_malloc(recent_zhist, file_desc, hdr->object_len, hdr->objhash);
+		if (NULL == shdr)
+		{	/* Most likely lseek or read of object file into shared memory failed. Possible for example
+			 * if the object file is truncated. Issue error.
+			 */
+			zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+		}
+		/* We need this link - continue setup */
+		assert(!memcmp(hdr, shdr, SIZEOF(rhdtyp))); /* we already read rtnhdr from disk, assert that is same as in shm */
+	}
+#	endif
 	/* Read in and/or relocate the pointers to the various sections. To understand the size calculations
 	 * being done note that the contents of the various xxx_adr pointers in the routine header are
 	 * initially the offsets from the start of the object. This is so we can address the various sections
@@ -372,6 +518,12 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	switch(linktyp)
 	{
 		case LINK_SHROBJ:
+			hdr->shared_object = TRUE;		/* Indicate this is linked as a shared object */
+#			ifdef AUTORELINK_SUPPORTED
+			zhent = recent_zhist->end - 1;
+			hdr->relinkctl_bkptr = zhent->relinkctl_bkptr;
+#			endif
+			/* Note - fall through */
 		case LINK_SHRLIB:
 			rel_base = shdr;
 			break;
@@ -382,7 +534,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 			assert((INTPTR_T)sect_ro_rel == ((INTPTR_T)sect_ro_rel & ~(LINKAGE_PSECT_BOUNDARY - 1)));
 			DOREADRC_OBJFILE(file_desc, sect_ro_rel, sect_ro_rel_size, status);
 			if (0 != status)
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 			/* The offset correction is the amount that needs to be applied to a given storage area that
 			 * is no longer contiguous with the routine header. In this case, the code and other sections
 			 * are no longer contiguous with the routine header but the initial offsets in the routine
@@ -428,6 +580,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	}
 	RELOCATE(hdr->lnrtab_adr, lnr_tabent *, rel_base);
 	RELOCATE(hdr->literal_text_adr, unsigned char *, rel_base);
+	RELOCATE(hdr->linkage_names, mstr *, rel_base);
 	if (dynlits)
 		RELOCATE(hdr->literal_adr, mval *, rel_base);
 	/* Read-write releasable section */
@@ -442,7 +595,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		case LINK_PPRIVOBJ:
 			DOREADRC_OBJFILE(file_desc, sect_rw_rel, sect_rw_rel_size, status);
 			if (0 != status)
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 			break;
 		default:
 			assert(FALSE /* Invalid link type */);
@@ -512,7 +665,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		case LINK_PPRIVOBJ:
 			DOREADRC_OBJFILE(file_desc, sect_rw_nonrel, sect_rw_nonrel_size, status);
 			if (0 != status)
-				zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+				zl_error(NULL, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 			break;
 		default:
 			assert(FALSE /* Invalid link type */);
@@ -525,7 +678,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		RELOCATE(curlbe->lnr_adr, lnr_tabent *, hdr->lnrtab_adr);
 	}
 	/* Remaining initialization */
-	hdr->zhist = TREF(recent_zhist);	/* TODO: Document what this is or change to different mechanism */
+	ARLINK_ONLY(assert(((NULL == recent_zhist) && (LINK_SHROBJ != linktyp))
+			   || ((NULL != recent_zhist) && (LINK_SHROBJ == linktyp))));
+	ARLINK_ONLY(hdr->zhist = recent_zhist);
 	hdr->current_rhead_adr = hdr;
 	assert(hdr->routine_name.len < SIZEOF(zlink_mname.c));
 	memcpy(&zlink_mname.c[0], hdr->routine_name.addr, hdr->routine_name.len);
@@ -537,7 +692,9 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	if (!addr_fix(file_desc, shdr, linktyp, &urx_lcl_anchor))
 	{
 		urx_free(&urx_lcl_anchor);
-		zl_error(linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
+		/* Decrement "refcnt" bump done by "rtnobj_shm_malloc" above */
+		ARLINK_ONLY(if (LINK_SHROBJ == linktyp) rtnobj_shm_free(hdr, LATCH_GRABBED_FALSE));
+		zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_INVOBJFILE, fname_len, fname, 0, NULL);
 	}
 	/* Register new routine in routine name vector displacing old one and performing any necessary cleanup */
 	if (!zlput_rname(hdr))
@@ -545,8 +702,14 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		urx_free(&urx_lcl_anchor);
 		/* Copy routine name to local variable because zl_error frees it. */
 		memcpy(&module_name.c[0], hdr->routine_name.addr, hdr->routine_name.len);
-		zl_error(linktyp, file_desc, ERR_LOADRUNNING, (int)hdr->routine_name.len, &module_name.c[0], 0, NULL);
+		/* Decrement "refcnt" bump done by "rtnobj_shm_malloc" above */
+		ARLINK_ONLY(if (LINK_SHROBJ == linktyp) rtnobj_shm_free(hdr, LATCH_GRABBED_FALSE));
+		zl_error(RECENT_ZHIST, linktyp, file_desc, ERR_LOADRUNNING, (int)hdr->routine_name.len, &module_name.c[0],
+			 0, NULL);
 	}
+	/* Now that new routine is registered, no longer need to do rtnobj_shm_free.
+	 * That will be done by relinkctl_rundown as part of scanning the rtn_names[] array.
+	 */
 	/* Fix up of routine headers for old versions of routine so they point to the newest version */
 	old_rhead = hdr->old_rhead_adr;
 	lbt_bot = hdr->labtab_adr;
@@ -578,6 +741,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		old_rhead->routine_name = hdr->routine_name;
 		old_rhead->vartab_len = hdr->vartab_len;
 		old_rhead->vartab_adr = hdr->vartab_adr;
+		old_rhead->shared_ptext_adr = hdr->shared_ptext_adr;
 		old_rhead->ptext_adr = hdr->ptext_adr;
 		old_rhead->ptext_end_adr = hdr->ptext_end_adr;
 		old_rhead->lnrtab_adr = hdr->lnrtab_adr;
@@ -589,7 +753,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 		old_rhead->literal_adr = hdr->literal_adr;
 		old_rhead->literal_text_adr = hdr->literal_text_adr;
 		old_rhead->literal_len = hdr->literal_len;
-		old_rhead->zhist = hdr->zhist;
+		ARLINK_ONLY(old_rhead->zhist = hdr->zhist);
 		old_rhead = (rhdtyp *)old_rhead->old_rhead_adr;
 	}
 	/* Add local unresolves to global chain freeing elements that already existed in the global chain */
@@ -598,6 +762,7 @@ boolean_t incr_link (int file_desc, zro_ent *zro_entry, uint4 fname_len, char *f
 	urx_resolve(hdr, (lab_tabent *)lbt_bot, (lab_tabent *)lbt_top);
 	if (LINK_PPRIVOBJ == linktyp)
 		cacheflush(hdr->ptext_adr, (hdr->ptext_end_adr - hdr->ptext_adr), BCACHE);
+	/* zOS cleanups */
 	ZOS_FREE_TEXT_SECTION;
 	/* Don't leave global pointers around to active blocks */
 	hdr = NULL;
@@ -891,12 +1056,12 @@ STATICFNDEF void res_free(res_list *root)
  *   len/addr   - length/address of 1st substitution string.
  *   len2/addr2 - length/address of 2nd substitution string.
  */
-STATICFNDEF void zl_error(linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2)
+STATICFNDEF void zl_error(void *recent_zhist, linktype linktyp, int4 file, int4 err, int4 len, char *addr, int4 len2, char *addr2)
 {
 	int rc;
 
 	ZOS_FREE_TEXT_SECTION;
-	zl_error_hskpng(linktyp, file);
+	zl_error_hskpng(linktyp, file, recent_zhist);
 	if (LINK_PPRIVOBJ == linktyp)
 	{	/* Only private process links have this area to free */
 		CLOSEFILE_RESET(file, rc);	/* resets "file" to FD_INVALID */
@@ -914,7 +1079,7 @@ STATICFNDEF void zl_error(linktype linktyp, int4 file, int4 err, int4 len, char
  *   linktyp    - type of linkage performed (enum linktype).
  *   file       - file descriptor of open file.
  */
-STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file)
+STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file, void *recent_zhist)
 {
 	if (NULL != hdr)
 	{
@@ -936,4 +1101,5 @@ STATICFNDEF void zl_error_hskpng(linktype linktyp, int4 file)
 		GTM_TEXT_FREE(sect_ro_rel);
 		sect_ro_rel = NULL;
 	}
+	RELEASE_RECENT_ZHIST;
 }
diff --git a/sr_unix/incr_link.h b/sr_unix/incr_link.h
index e78a59a..282deb7 100644
--- a/sr_unix/incr_link.h
+++ b/sr_unix/incr_link.h
@@ -17,10 +17,34 @@
 
 #ifdef USHBIN_SUPPORTED
 #include <incr_link_sp.h>
+#endif
+#include "zroutinessp.h"	/* need zro_ent typedef */
+
+/* If autorelink is supported, the additional recent_zhist parameter (if non-NULL) points to a malloc'd search history buffer
+ * which should be* released for any error. This macro provides the release capability.
+ */
+#ifdef AUTORELINK_SUPPORTED
+#  define RECENT_ZHIST recent_zhist
+#  define RELEASE_RECENT_ZHIST 					\
+{								\
+	if (NULL != recent_zhist)				\
+	{							\
+		free(recent_zhist);				\
+		recent_zhist = NULL;				\
+	}							\
+}
 #else
-#include "zroutinessp.h"	/* need zro_ent typedef for i386 dummy argument */
+#  define RECENT_ZHIST NULL
+#  define RELEASE_RECENT_ZHIST
 #endif
+
+#ifdef AUTORELINK_SUPPORTED
+# define INCR_LINK(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME) incr_link(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME)
+boolean_t incr_link(int file_desc, zro_ent *zro_entry, zro_hist *recent_zhist_ptr, uint4 fname_len, char *fname);
+#else
+# define INCR_LINK(FD, ZRO_ENT, ZRO_HIST, FNLEN, FNAME) incr_link(FD, ZRO_ENT, FNLEN, FNAME)
 boolean_t incr_link(int file_desc, zro_ent *zro_entry, uint4 fname_len, char *fname);
+#endif
 
 #ifdef __MVS__
 #define ZOS_FREE_TEXT_SECTION 		\
diff --git a/sr_unix/init_gtm.c b/sr_unix/init_gtm.c
index 3a114ef..a76791c 100644
--- a/sr_unix/init_gtm.c
+++ b/sr_unix/init_gtm.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -51,8 +51,6 @@ GBLREF void		(*tp_timeout_action_ptr)(void);
 GBLREF void		(*tp_timeout_clear_ptr)(void);
 GBLREF void		(*tp_timeout_start_timer_ptr)(int4 tmout_sec);
 GBLREF int		(*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
-GBLREF void		(*op_write_ptr)(mval *v);
-GBLREF void		(*op_wteol_ptr)(int4 n);
 GBLREF void		(*unw_prof_frame_ptr)(void);
 GBLREF void		(*stx_error_fptr)(int in_error, ...);	/* Function pointer for stx_error() so gtm_utf8.c can avoid pulling
 								 * stx_error() into gtmsecshr, and thus just about everything else
@@ -113,8 +111,6 @@ void init_gtm(void)
 	ctrlc_handler_ptr = ctrlc_handler;
 	if (MUMPS_UTILTRIGR != invocation_mode)
 		op_open_ptr = op_open;
-	op_write_ptr = op_write;
-	op_wteol_ptr = op_wteol;
 	unw_prof_frame_ptr = unw_prof_frame;
 	stx_error_fptr = stx_error;
 	show_source_line_fptr = show_source_line;
diff --git a/sr_unix/interlock.h b/sr_unix/interlock.h
index 3125629..e1af33a 100644
--- a/sr_unix/interlock.h
+++ b/sr_unix/interlock.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -102,9 +102,13 @@
 #endif /* __ia64, __x86_64__, and __sparc */
 /* Use COMPSWAP_UNLOCK to release the lock because of the memory barrier and other-processor notification it implies. Also
  * the usage of COMPSWAP_UNLOCK allows us to check (with low cost) that we have/had the lock we are trying to release.
- * If we don't have the lock and are trying to release it, a GTMASSERT seems the logical choice as the logic is very broken
- * at that point. If this macro is used in part of an expression, the GTMASSERT path must also return a value (to keep
- * the compiler happy) thus the construct (GTMASSERT, 0) which returns a zero (see usage with assert() on UNIX).
+ * If we don't have the lock and are trying to release it, an assertpro seems the logical choice as the logic is very broken
+ * at that point. If this macro is used in part of an expression, the assertpro path must also return a value (to keep
+ * the compiler happy) thus the construct (assertpro, 0) which returns a zero (see usage with assert() on UNIX).
  */
-#define RELEASE_SWAPLOCK(X)		(COMPSWAP_UNLOCK((X), process_id, 0, LOCK_AVAILABLE, 0) ? 1 : (GTMASSERT, 0))
+#define RELEASE_SWAPLOCK(X)		(COMPSWAP_UNLOCK((X), process_id, 0, LOCK_AVAILABLE, 0) ? 1 : (assertpro(FALSE), 0))
+
+/* Function prototypes */
+boolean_t	grab_latch(sm_global_latch_ptr_t latch, int max_timeout_in_secs);
+void		rel_latch(sm_global_latch_ptr_t latch);
 
diff --git a/sr_unix/iopi_open.c b/sr_unix/iopi_open.c
index 4b37616..265121e 100644
--- a/sr_unix/iopi_open.c
+++ b/sr_unix/iopi_open.c
@@ -38,6 +38,8 @@
 #include "gtm_zos_io.h"
 #include "gtm_zos_chset.h"
 #endif
+#include "send_msg.h"
+#include "wbox_test_init.h"
 
 LITREF	unsigned char		io_params_size[];
 ZOS_ONLY(GBLREF boolean_t	gtm_tag_utf8_as_ascii;)
@@ -50,6 +52,13 @@ error_def(ERR_SYSCALL);
 error_def(ERR_TEXT);
 ZOS_ONLY(error_def(ERR_BADTAG);)
 
+enum
+{
+	PARSE_OK = 1,		/* the parse passed */
+	PARSE_FAIL,		/* the parse failed but $PATH is defined in the environment */
+	PARSE_FAIL_NOPATH	/* the parse failed and $PATH is undefined in the environment */
+};
+
 #define FREE_ALL { if (NULL != copy_cmd_string) free(copy_cmd_string); if (NULL != temp) free(temp);\
 		if (NULL != buf)  free(buf); if (NULL != dir_in_path) free(dir_in_path);if (NULL != command2) free(command2); }
 
@@ -109,11 +118,11 @@ int parse_pipe(char *cmd_string, char *ret_token)
 	int env_inc;
 	struct stat sb;
 	char *path, path_buff[GTM_PATH_MAX];
-	char *temp;
-	char *buf;
-	char *dir_in_path;
-	char *command2;
-	char *copy_cmd_string;
+	char *temp = NULL;
+	char *buf = NULL;
+	char *dir_in_path = NULL;
+	char *command2 = NULL;
+	char *copy_cmd_string = NULL;
 	char *token1;
 	char *token2;
 	char *token3;
@@ -123,17 +132,20 @@ int parse_pipe(char *cmd_string, char *ret_token)
 	int cmd_string_size;
 
 	path = GETENV("PATH");
-	path_len = STRLEN(path);
-	if (GTM_PATH_MAX <= path_len)
-		path_len = GTM_PATH_MAX - 1;
-	memcpy(path_buff, path, path_len + 1);	/* + 1 for null */
-	path = path_buff;
+	if (NULL != path)
+	{
+		path_len = STRLEN(path);
+		if (GTM_PATH_MAX <= path_len)
+			path_len = GTM_PATH_MAX - 1;
+		memcpy(path_buff, path, path_len + 1);	/* + 1 for null */
+		path = path_buff;
+		dir_in_path = (char *)malloc(GTM_PATH_MAX);
+	}
 
 	cmd_string_size = STRLEN(cmd_string) + 1;
 	pathsize = GTM_PATH_MAX + cmd_string_size;
 	buf = (char *)malloc(pathsize);
 	copy_cmd_string = (char *)malloc(cmd_string_size);
-	dir_in_path = (char *)malloc(GTM_PATH_MAX);
 	command2 = (char *)malloc(cmd_string_size);
 	temp = (char *)malloc(pathsize);
 	memcpy(copy_cmd_string, cmd_string, cmd_string_size);
@@ -148,7 +160,7 @@ int parse_pipe(char *cmd_string, char *ret_token)
 			break;
 
 		/* separate into tokens using space as delimiter */
-		/* if the first token is a non-alpha-numeric or if it is nohup the skip it */
+		/* if the first token is a non-alpha-numeric or if it is nohup then skip it */
 		/* and use the next one as a command to find */
 		memcpy(command2, token1, STRLEN(token1) + 1);
 
@@ -176,18 +188,19 @@ int parse_pipe(char *cmd_string, char *ret_token)
 			/* if the first character is a $ sign then assume it is an environment variable used
 			   like $gtm_dist/mupip.  Get the environment variable and substitute it. */
 			notfound = TRUE;
+			temp[0] = '\0';
 			if ('$' == *token2)
 			{
 				for (env_inc = 1; '/' != *(token2 + env_inc); env_inc++)
 				{
 					temp[env_inc - 1] = *(token2 + env_inc);
 				}
-				temp[env_inc] = '\0';
+				temp[env_inc - 1] = '\0';
 				env_var = GETENV(temp);
 				if (NULL != env_var)
 				{
 					/* build a translated path to command */
-					assert(cmd_string_size > (STRLEN(token2 + env_inc) + STRLEN(env_var)));
+					assert(pathsize > (STRLEN(token2 + env_inc) + STRLEN(env_var)));
 					SPRINTF(temp, "%s%s", env_var, token2 + env_inc);
 
 					/* The command must be a regular file and executable */
@@ -215,21 +228,24 @@ int parse_pipe(char *cmd_string, char *ret_token)
 					notfound = TRUE;
 			}
 
-			/* search all the directories in the $PATH */
-			memcpy(dir_in_path, path, path_len + 1);
-			for (str3= dir_in_path; TRUE == notfound; str3 = NULL)
+			/* search all the directories in the $PATH if defined */
+			if (NULL != path)
 			{
-				token3 = strtok_r(str3, ":", &saveptr3);
-				if (NULL == token3)
-					break;
-				SPRINTF(buf, "%s/%s", token3, token2);
-				notfound = TRUE;
-				/* The command must be a regular file and executable */
-				STAT_FILE(buf, &sb, ret_stat);
-				if (0 == ret_stat && (S_ISREG(sb.st_mode)) && (sb.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+				memcpy(dir_in_path, path, path_len + 1);
+				for (str3 = dir_in_path; TRUE == notfound; str3 = NULL)
 				{
-					notfound = FALSE;
-					break;
+					token3 = strtok_r(str3, ":", &saveptr3);
+					if (NULL == token3)
+						break;
+					SPRINTF(buf, "%s/%s", token3, token2);
+					notfound = TRUE;
+					/* The command must be a regular file and executable */
+					STAT_FILE(buf, &sb, ret_stat);
+					if (0 == ret_stat && (S_ISREG(sb.st_mode)) && (sb.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)))
+					{
+						notfound = FALSE;
+						break;
+					}
 				}
 			}
 		}
@@ -238,11 +254,14 @@ int parse_pipe(char *cmd_string, char *ret_token)
 			assert(GTM_PATH_MAX > (STRLEN(token2) + 1));
 			memcpy(ret_token, token2, STRLEN(token2) + 1);
 			FREE_ALL;
-			return(FALSE);
+			if (NULL != path)
+				return(PARSE_FAIL);
+			else
+				return(PARSE_FAIL_NOPATH);
 		}
 	}
 	FREE_ALL;
-	return(TRUE);
+	return(PARSE_OK);
 }
 
 /* When we are in this routine dev_name is same as naml in io_open_try() */
@@ -256,6 +275,7 @@ int parse_pipe(char *cmd_string, char *ret_token)
 }
 
 #define INVALID_CMD "Invalid command string: "
+#define INVALID_CMD2 "$PATH undefined, Invalid command string: "
 
 short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
 {
@@ -286,11 +306,12 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
 	char 		*sh;
 	int		independent = FALSE;
 	int		parse = FALSE;
+	int		parse_result;
 	int 		status_read;
 	int		return_stdout = TRUE;
 	int		return_stderr = FALSE;
 	char		ret_token[GTM_MAX_DIR_LEN];
-	char		error_str[MAXDEVPARLEN + STR_LIT_LEN(INVALID_CMD)];
+	char		error_str[MAXDEVPARLEN + STR_LIT_LEN(INVALID_CMD2)];
 	int		save_errno;
 	int		flags;
 	int		fcntl_res, rc;
@@ -302,7 +323,11 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
 	boolean_t	textflag;
 	int		ccsid, status, realfiletag;
 #endif
+#	ifdef DEBUG
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
+#	endif
 	iod = dev_name->iod;
 
 	while (iop_eol != *(pp->str.addr + p_offset))
@@ -365,10 +390,13 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
 		pcommand[slen[PCOMMAND]] = '\0';
 		if (TRUE == parse)
 		{
-			if (FALSE == parse_pipe(pcommand, ret_token))
+			if (PARSE_OK != (parse_result = parse_pipe(pcommand, ret_token)))
 			{
 				PIPE_ERROR_INIT();
-				SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token);
+				if (PARSE_FAIL == parse_result)
+					SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token);
+				else
+					SPRINTF(error_str, "%s%s", INVALID_CMD2, ret_token);
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
 					  ERR_TEXT, 2, LEN_AND_STR(error_str));
 			}
@@ -515,49 +543,52 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
 
 		CLOSEFILE(0, rc);
 		/* stdin becomes pfd_write[0] */
-		if (-1 == dup2(pfd_write[0], 0))
+		if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDIN) ||) (-1 == dup2(pfd_write[0], 0)))
 		{
 			save_errno = errno;
 			PIPE_ERROR_INIT();
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
-				  ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_write[0]) failed in child"), save_errno);
+			send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+				  ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_write[0]) failed in child"));
+			_exit(ERR_DEVOPENFAIL);
 		}
 		if (return_stdout)
 		{
 			/* stdout becomes pfd_read[1] */
 			CLOSEFILE(1, rc);
-			if (-1 == dup2(pfd_read[1], 1))
+			if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDOUT) ||) (-1 == dup2(pfd_read[1], 1)))
 			{
 				save_errno = errno;
 				PIPE_ERROR_INIT();
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
-					  ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_read[1],1) failed in child"), save_errno);
+				send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+					  ERR_TEXT, 2, LEN_AND_LIT("PIPE - dup2(pfd_read[1],1) failed in child"));
+				_exit(ERR_DEVOPENFAIL);
 			}
 			/* stderr also becomes pfd_read[1] if return_stderr is false*/
 			if (FALSE == return_stderr)
 			{
 				CLOSEFILE(2, rc);
-				if (-1 == dup2(pfd_read[1], 2))
+				if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDERR1) ||) (-1 == dup2(pfd_read[1], 2)))
 				{
 					save_errno = errno;
 					PIPE_ERROR_INIT();
-					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
+					send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
 							dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
-							LEN_AND_LIT("PIPE - dup2(pfd_read[1],2) failed in child"), save_errno);
+							LEN_AND_LIT("PIPE - dup2(pfd_read[1],2) failed in child"));
+					_exit(ERR_DEVOPENFAIL);
 				}
 			}
 		}
 		if (return_stderr)
 		{
 			CLOSEFILE(2, rc);
-			if (-1 == dup2(pfd_read_stderr[1], 2))
+			if (DEBUG_ONLY(WBTEST_ENABLED(WBTEST_BADDUP_PIPE_STDERR2) ||) (-1 == dup2(pfd_read_stderr[1], 2)))
 			{
 				save_errno = errno;
 				PIPE_ERROR_INIT();
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
+				send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2,
 						dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
-						LEN_AND_LIT("PIPE - dup2(pfd_read_stderr[1],2) failed in child"),
-						save_errno);
+						LEN_AND_LIT("PIPE - dup2(pfd_read_stderr[1],2) failed in child"));
+				_exit(ERR_DEVOPENFAIL);
 			}
 		}
 		if (0 == slen[PSHELL])
@@ -569,18 +600,23 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
 			{
 				ret = EXECL("/bin/sh", "sh", "-c", pcommand, (char *)NULL);
 			} else
-				ret = EXECL(sh, basename(sh), "-c", pcommand, (char *)NULL);
+				if (!WBTEST_ENABLED(WBTEST_BADEXEC_PIPE_PROCESS))
+					ret = EXECL(sh, basename(sh), "-c", pcommand, (char *)NULL);
+				else
+					ret = -1;
 		} else
 			ret = EXECL(pshell, pshell_name, "-c", pcommand, (char *)NULL);
 		if (-1 == ret)
 		{
 			save_errno = errno;
 			PIPE_ERROR_INIT();
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
-				  ERR_TEXT, 2, LEN_AND_LIT("PIPE - execl() failed in child"), save_errno);
+			send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+				  ERR_TEXT, 2, LEN_AND_LIT("PIPE - execl() failed in child"));
+			_exit(-1);
 		}
 	} else
 	{	/* in parent */
+		DEBUG_ONLY(TREF(fork_without_child_wait) = TRUE);	/* set variable to help assert in "relinkctl_rundown()" */
 		CLOSEFILE_RESET(pfd_write[0], rc);          /* Close unused read end; Resets "pfd_write[0]" to FD_INVALID */
 		ZOS_ONLY(if (-1 == gtm_zos_setcvtmode(pfd_write[1], write_cvt[PARENTCVT]))
 			TAG_POLICY_SEND_MSG("PIPE - conversion mode(pfd_write) failed", errno, realfiletag, ccsid));
diff --git a/sr_unix/iosocket_tls.c b/sr_unix/iosocket_tls.c
new file mode 100644
index 0000000..8fadbf8
--- /dev/null
+++ b/sr_unix/iosocket_tls.c
@@ -0,0 +1,357 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 GTM_TLS
+
+#include <errno.h>
+#ifdef USE_POLL
+#include <poll.h>
+#else
+#include "gtm_select.h"
+#endif
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include "eintr_wrappers.h"
+
+#include "io.h"
+#include "gt_timer.h"
+#include "iosocketdef.h"
+#include "gtm_conv.h"
+#include "gtm_utf8.h"
+#include "rel_quant.h"
+#include "send_msg.h"
+#include "error.h"
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "fgncalsp.h"
+#include "iotimer.h"
+#include "gtm_tls.h"
+
+GBLREF io_pair			io_curr_device;
+GBLREF char			dl_err[MAX_ERRSTR_LEN];
+GBLREF int			dollar_truth;
+
+GBLREF	gtm_tls_ctx_t		*tls_ctx;
+
+error_def(ERR_CURRSOCKOFR);
+error_def(ERR_TLSCONVSOCK);
+error_def(ERR_TLSDLLNOOPEN);
+error_def(ERR_TLSHANDSHAKE);
+error_def(ERR_TLSINIT);
+error_def(ERR_TLSPARAM);
+error_def(ERR_TLSRENEGOTIATE);
+error_def(ERR_NOSOCKETINDEV);
+error_def(ERR_SOCKPASSDATAMIX);
+error_def(ERR_TEXT);
+error_def(ERR_ZINTRECURSEIO);
+
+#define	MAX_TLSOPTION	12
+
+typedef enum
+{
+	tlsopt_invalid,
+	tlsopt_client,
+	tlsopt_server,
+	tlsopt_renegotiate
+} tls_option;
+
+void	iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg)
+{	/* note extraarg is not currently used */
+	int4			length, flags, timeout, msec_timeout, status, status2, len, errlen, devlen, tls_errno, save_errno;
+	io_desc			*iod;
+	d_socket_struct 	*dsocketptr;
+	socket_struct		*socketptr;
+	char			optionstr[MAX_TLSOPTION], idstr[MAX_TLSID_LEN], passwordstr[GTM_PASSPHRASE_MAX_ASCII + 1];
+	const char		*errp;
+	tls_option		option;
+	gtm_tls_socket_t	*tlssocket;
+	ABS_TIME		cur_time, end_time;
+#	ifdef USE_POLL
+	struct pollfd		fds;
+#	else
+	fd_set			fds, *readfds, *writefds;
+	struct timeval		timeout_spec, *timeout_ptr;
+#	endif
+
+	iod = io_curr_device.out;
+	assert(gtmsocket == iod->type);
+	dsocketptr = (d_socket_struct *)iod->dev_sp;
+	if (0 >= dsocketptr->n_socket)
+	{
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV);
+		return;
+	}
+	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);
+	socketptr = dsocketptr->socket[dsocketptr->current_socket];
+	ENSURE_DATA_SOCKET(socketptr);
+	if (socket_tcpip != socketptr->protocol)
+	{
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, RTS_ERROR_MVAL(optionmval),
+			LEN_AND_LIT("but socket is not TCP"));
+		return;
+	}
+	if (socket_connected != socketptr->state)
+	{
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"),
+			LEN_AND_LIT("but socket not connected"));
+		return;
+	}
+	if (NULL != tlsid)
+	{
+		length = tlsid->str.len;
+		if (MAX_TLSID_LEN < (length + 1))	/* for null */
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("TLSID"), LEN_AND_LIT("too long"));
+			return;
+		}
+		STRNCPY_STR(idstr, tlsid->str.addr, length);
+		idstr[length] = '\0';
+	} else
+		idstr[0] = '\0';
+	if (NULL != password)
+	{
+		length = password->str.len;
+		if (GTM_PASSPHRASE_MAX_ASCII < length)
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"),
+				LEN_AND_LIT("too long"));
+			return;
+		}
+		STRNCPY_STR(passwordstr, password->str.addr, length);
+		passwordstr[length] = '\0';
+	} else
+		passwordstr[0] = '\0';
+	length = MIN(MAX_TLSOPTION, optionmval->str.len);
+	lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length);
+	if (0 == memcmp(optionstr, "CLIENT", length))
+		option = tlsopt_client;
+	else if (0 == memcmp(optionstr, "SERVER", length))
+		option = tlsopt_server;
+	else if (0 == memcmp(optionstr, "RENEGOTIATE", length))
+		option = tlsopt_renegotiate;
+	else
+		option = tlsopt_invalid;
+	memcpy(iod->dollar.device, "0", SIZEOF("0"));
+	if (NO_M_TIMEOUT != timeoutarg)
+	{
+		msec_timeout = timeout2msec(timeoutarg);
+		sys_get_curr_time(&cur_time);
+		add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+	} else
+		msec_timeout = -1;
+	if ((tlsopt_client == option) || (tlsopt_server == option))
+	{	/* most of the setup is common */
+		if (socketptr->tlsenabled)
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+				LEN_AND_LIT("but TLS already enabled"));
+			return;
+		}
+		assertpro((0 >= socketptr->buffered_length) && (0 >= socketptr->obuffer_length));
+		if (NULL == tls_ctx)
+		{	/* first use of TLS */
+			if (-1 == gtm_tls_loadlibrary())
+			{
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0, ERR_TEXT, 2, LEN_AND_STR(dl_err));
+				return;
+			}
+			if (NULL == (tls_ctx = (gtm_tls_init(GTM_TLS_API_VERSION, GTMTLS_OP_INTERACTIVE_MODE))))
+			{
+				errp = gtm_tls_get_error();
+				len = SIZEOF(ONE_COMMA) - 1;
+				memcpy(iod->dollar.device, ONE_COMMA, len);
+				errlen = STRLEN(errp);
+				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+				memcpy(&iod->dollar.device[len], errp, devlen + 1);
+				if (devlen < errlen)
+					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+				if (socketptr->ioerror)
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0, ERR_TEXT, 2, errlen, errp);
+				if (NO_M_TIMEOUT != timeoutarg)
+					dollar_truth = FALSE;
+				return;
+			}
+		}
+		socketptr->tlsenabled = TRUE;
+		flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0);
+		socketptr->tlssocket = gtm_tls_socket(tls_ctx, NULL, socketptr->sd, idstr, flags);
+		if (NULL == socketptr->tlssocket)
+		{
+			socketptr->tlsenabled = FALSE;
+			errp = gtm_tls_get_error();
+			len = SIZEOF(ONE_COMMA) - 1;
+			memcpy(iod->dollar.device, ONE_COMMA, len);
+			errlen = STRLEN(errp);
+			devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+			memcpy(&iod->dollar.device[len], errp, devlen + 1);
+			if (devlen < errlen)
+				iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+			if (socketptr->ioerror)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp);
+			if (NO_M_TIMEOUT != timeoutarg)
+				dollar_truth = FALSE;
+			return;
+		}
+		status = 0;
+#		ifndef	USE_POLL
+		if (NO_M_TIMEOUT == timeoutarg)
+			timeout_ptr = NULL;
+		else
+		{
+			timeout_spec.tv_sec = msec_timeout / 1000;
+			timeout_spec.tv_usec = (msec_timeout % 1000) * 1000;	/* remainder in millsecs to microsecs */
+			timeout_ptr = &timeout_spec;
+		}
+#		endif
+		do
+		{
+			status2 = 0;
+			if (0 != status)
+			{
+#				ifdef USE_POLL
+				fds.fd = socketptr->sd;
+				fds.events = (GTMTLS_WANT_READ == status) ? POLLIN : POLLOUT;
+#				else
+				readfds = writefds = NULL;
+				assertpro(FD_SETSIZE > socketptr->sd);
+				FD_ZERO(&fds);
+				FD_SET(socketptr->sd, &fds);
+				writefds = (GTMTLS_WANT_WRITE == status) ? &fds : NULL;
+				readfds = (GTMTLS_WANT_READ == status) ? &fds : NULL;
+#				endif
+				POLL_ONLY(if (-1 == (status2 = poll(&fds, 1, msec_timeout))))
+				SELECT_ONLY(if (-1 == (status2 = select(socketptr->sd + 1, readfds, writefds, NULL, timeout_ptr))))
+				{
+					save_errno = errno;
+					if (EAGAIN == save_errno)
+					{
+						rel_quant();	/* allow resources to become available */
+						status2 = 0;	/* treat as timeout */
+					} else if (EINTR == save_errno)
+						status2 = 0;
+				}
+			} else
+				status2 = 1;	/* do accept/connect first time */
+			if (0 < status2)
+			{
+				if (tlsopt_server == option)
+					status = gtm_tls_accept((gtm_tls_socket_t *)socketptr->tlssocket);
+				else
+					status = gtm_tls_connect((gtm_tls_socket_t *)socketptr->tlssocket);
+			}
+			if ((0 > status2) || ((status != 0) && ((GTMTLS_WANT_READ != status) && (GTMTLS_WANT_WRITE != status))))
+			{
+				if (0 != status)
+				{
+					tls_errno = gtm_tls_errno();
+					if (0 > tls_errno)
+						errp = gtm_tls_get_error();
+					else
+						errp = STRERROR(tls_errno);
+				} else
+					errp = STRERROR(save_errno);
+				socketptr->tlsenabled = FALSE;
+				len = SIZEOF(ONE_COMMA) - 1;
+				memcpy(iod->dollar.device, ONE_COMMA, len);
+				errlen = STRLEN(errp);
+				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+				memcpy(&iod->dollar.device[len], errp, devlen + 1);
+				if (devlen < errlen)
+					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+				if (socketptr->ioerror)
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSHANDSHAKE, 0,
+						ERR_TEXT, 2, errlen, errp);
+				return;
+			}
+			if ((0 != status) && (0 <= status2))	/* not accepted/connected and not error */
+			{	/* check for timeout if not error or want read or write */
+				if ((0 != timeoutarg) && (NO_M_TIMEOUT != timeoutarg))
+				{
+					sys_get_curr_time(&cur_time);
+					cur_time = sub_abs_time(&end_time, &cur_time);
+					if (0 >= cur_time.at_sec)
+					{	/* no more time */
+						gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+						socketptr->tlsenabled = FALSE;
+						dollar_truth = FALSE;
+						return;
+					} else
+					{	/* adjust msec_timeout for poll/select */
+#					ifdef	USE_POLL
+						msec_timeout = (cur_time.at_sec * 1000) + (cur_time.at_usec / 1000);
+#					else
+						timeout_spec.tv_sec = cur_time.at_sec;
+						timeout_spec.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
+#					endif
+					}
+				} else if (0 == timeoutarg)
+				{	/* only one chance */
+					gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
+					socketptr->tlsenabled = FALSE;
+					dollar_truth = FALSE;
+					return;
+				}
+				continue;
+			}
+		} while ((GTMTLS_WANT_READ == status) || (GTMTLS_WANT_WRITE == status));
+		/* turn on output buffering */
+		if (0 == socketptr->obuffer_size)
+			socketptr->obuffer_size = socketptr->buffer_size;
+		socketptr->obuffer_length = socketptr->obuffer_offset = 0;
+		socketptr->obuffer_wait_time = DEFAULT_WRITE_WAIT;
+		socketptr->obuffer_flush_time = DEFAULT_WRITE_WAIT * 2;	/* until add device parameter */
+		socketptr->obuffer = malloc(socketptr->obuffer_size);
+	} else if (tlsopt_renegotiate == option)
+	{
+		if (!socketptr->tlsenabled)
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+				LEN_AND_LIT("but TLS not enabled"));
+			return;		/* make compiler and analyzers happy */
+		}
+		/* TODO: allow verify-mode options in idstr */
+		status = gtm_tls_renegotiate((gtm_tls_socket_t *)socketptr->tlssocket);
+		if (0 != status)
+		{
+			tls_errno = gtm_tls_errno();
+			if (0 > tls_errno)
+				errp = gtm_tls_get_error();
+			else
+				errp = STRERROR(tls_errno);
+			len = SIZEOF(ONE_COMMA) - 1;
+			memcpy(iod->dollar.device, ONE_COMMA, len);
+			errlen = STRLEN(errp);
+			devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
+			memcpy(&iod->dollar.device[len], errp, devlen + 1);
+			if (devlen < errlen)
+				iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
+			if (socketptr->ioerror)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSRENEGOTIATE, 0,
+					ERR_TEXT, 2, errlen, errp);
+			return;
+		}
+	} else
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
+			LEN_AND_LIT("not a valid option"));
+	if (NO_M_TIMEOUT != timeoutarg)
+		dollar_truth = TRUE;
+	return;
+}
+#endif
diff --git a/sr_unix/jnlpool_init.c b/sr_unix/jnlpool_init.c
index 2acb5ae..cf2f7cb 100644
--- a/sr_unix/jnlpool_init.c
+++ b/sr_unix/jnlpool_init.c
@@ -959,7 +959,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
 			assert(NULL != gtmsourcelocal_ptr);
 			QWASSIGNDW(gtmsourcelocal_ptr->read_addr, 0);
 			gtmsourcelocal_ptr->read = 0;
-			gtmsourcelocal_ptr->read_state = READ_POOL;
+			gtmsourcelocal_ptr->read_state = gtmsourcelocal_ptr->jnlfileonly ? READ_FILE : READ_POOL;
 			gtmsourcelocal_ptr->mode = gtmsource_options.mode;
 			gtmsourcelocal_ptr->statslog = FALSE;
 			gtmsourcelocal_ptr->shutdown = NO_SHUTDOWN;
diff --git a/sr_unix/jobchild_init.c b/sr_unix/jobchild_init.c
index 91c8647..eece2b0 100644
--- a/sr_unix/jobchild_init.c
+++ b/sr_unix/jobchild_init.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -61,7 +61,7 @@ CONDITION_HANDLER(job_init_ch)
 /* Child process test and initialization. If this copy of GTM is a child process, then initialize the child. */
 void jobchild_init(void)
 {
-	unsigned int	status;
+	boolean_t	need_rtnobj_shm_free;
 	job_params_type	jparms;
 	unsigned char	*transfer_addr;		/* Transfer data */
 	rhdtyp		*base_addr;
@@ -71,7 +71,7 @@ void jobchild_init(void)
 	mval		job_args[MAX_ACTUALS];
 	mstr		routine, label;
 	int		offset;
-	int		rc;
+	int		status;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -84,7 +84,8 @@ void jobchild_init(void)
 		/* read parameters into parameter structure  - references CHILD_FLAG_ENV */
 		ojchildparms(&jparms, &job_arglist, job_args);
 		/* Clear the environment variable so that subsequent child mumps processes can start normal initialization. */
-		if (PUTENV(CLEAR_CHILD_FLAG_ENV))
+		PUTENV(status, CLEAR_CHILD_FLAG_ENV);
+		if (status)
 		{
 			util_out_print("Unable to clear gtmj0 process !UL exiting.", TRUE, process_id);
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
@@ -92,14 +93,17 @@ void jobchild_init(void)
 		/* Execute the command to be run before executing the actual M routine */
 		if (jparms.startup.len)
 		{
-			rc = SYSTEM(jparms.startup.addr);
-			if (-1 == rc)
+			status = SYSTEM(jparms.startup.addr);
+			if (-1 == status)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBSTARTCMDFAIL, 0, errno);
-			else if (0 != rc)
+			else if (0 != status)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_JOBSTARTCMDFAIL, 0);
 		}
-		if(!job_addr(&jparms.routine, &jparms.label, jparms.offset,
-				(char **)&base_addr, (char **)&transfer_addr))
+		/* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+		 * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+		 */
+		if (!job_addr(&jparms.routine, &jparms.label, jparms.offset,
+				(char **)&base_addr, (char **)&transfer_addr, &need_rtnobj_shm_free))
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
 		/* Set process priority */
 		if (jparms.baspri)
@@ -136,7 +140,11 @@ void jobchild_init(void)
 			if (!cli_get_str("INFILE", run_file_name, &arg_len))
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RUNPARAMERR);
 			lref_parse((uchar_ptr_t)run_file_name, &routine, &label, &offset);
-			if(!job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr))
+			/* See comment in ojstartchild.c about "need_rtnobj_shm_free". It is not used here because we will
+			 * decrement rtnobj reference counts at exit time in relinkctl_rundown (called by gtm_exit_handler).
+			 */
+			if (!job_addr(&routine, &label, offset, (char **)&base_addr,
+					(char **)&transfer_addr, &need_rtnobj_shm_free))
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
 		} else if (MUMPS_CALLIN & invocation_mode) /* call-in mode */
 		{
diff --git a/sr_unix/jobsp.h b/sr_unix/jobsp.h
index 71a50a2..928785d 100644
--- a/sr_unix/jobsp.h
+++ b/sr_unix/jobsp.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -19,6 +19,7 @@
 #define MAX_PRCNAM_LEN		15
 #define MAX_STDIOE_LEN		1024
 #define MAX_JOBPARM_LEN		1024
+
 #define TIMEOUT_ERROR		(MAX_SYSERR + 1)	/* a special value to differentiate it from the rest of errno's */
 
 #define CHILD_FLAG_ENV		"gtmj0"
@@ -106,6 +107,7 @@ typedef	struct
 	job_parm	*parms;
 	size_t		input_prebuffer_size;
 	char		*input_prebuffer;
+	boolean_t	passcurlvn;
 } job_params_type;
 
 typedef enum
@@ -126,7 +128,9 @@ typedef enum
 	job_done,			/* last message */
 	job_set_params,			/* followed by a job_params_msg message */
 	job_set_parm_list,		/* followed by a job_arg_count_msg and "arg_count" job_arg_msg messages */
-	job_set_input_buffer		/* followed by a job_buffer_size_msg and a data message of "buffer_size" */
+	job_set_input_buffer,		/* followed by a job_buffer_size_msg and a data message of "buffer_size" */
+	job_set_locals,			/* followed by local_variable */
+	local_trans_done		/* Indicates all of the locals have been sent to the grandchild */
 } job_setup_op;
 
 typedef struct
@@ -166,5 +170,5 @@ int ojstartchild(job_params_type *jparms, int argcnt, boolean_t *non_exit_return
 void ojparams(char *p, job_params_type *job_params);
 void ojgetch_env(job_params_type *jparms);
 void ojchildioclean(void);
-
+void ojmidchild_send_var(void);
 #endif
diff --git a/sr_unix/kitstart.csh b/sr_unix/kitstart.csh
index cb63b62..614c394 100644
--- a/sr_unix/kitstart.csh
+++ b/sr_unix/kitstart.csh
@@ -194,7 +194,7 @@ chmod 444 $readme_txt
 # be copied as a part of open source distribution (down the script)
 set open_source = 0
 set GNU_COPYING_license = "${gtm_com}/COPYING"
-if (("$osname" == "linux" && ( "$arch" == "i686" || "x8664" == "$arch" )) || ("$osname" == "osf1" && "$arch" == "alpha")) then
+if (("$osname" == "linux" && ( "$arch" == "i586" || "x8664" == "$arch" )) || ("$osname" == "osf1" && "$arch" == "alpha")) then
 	set open_source = 1
 	/bin/cp -pf $cms_tools/opensource_COPYING $GNU_COPYING_license
 	chmod 444 $GNU_COPYING_license
@@ -323,7 +323,7 @@ foreach image ($imagetype)
 	# no directories to be writeable for group or world if aix or 32-bit linux, otherwise for all
 	chmod a+x configure
 	chmod a+x gtminstall
-	if ((aix == ${osname}) || ((linux == ${osname}) && (i686 == "$arch"))) then
+	if ((aix == ${osname}) || ((linux == ${osname}) && ("i586" == "$arch"))) then
 		find . -type d -exec chmod go-w {} \;
 	else
 		find . -type d -exec chmod a-w {} \;
@@ -388,9 +388,9 @@ if ($testinstall) then
 		# blank line for default group
 		# V54003 now asks whether or not to retain .o files if libgtmutil.so is created
 		# We answer "y" to this question
-		# If libgtmutil.so is not created(on i686) this question is not asked
+		# If libgtmutil.so is not created(on i586) this question is not asked
 		if ("$osname" != "osf1") then
-			if ("$osname" == "linux" && "$arch" == "i686") then
+			if ("$osname" == "linux" && "$arch" == "i586") then
 				sh ./configure << CONFIGURE_EOF
 
 
@@ -438,9 +438,9 @@ CONFIGURE_EOF
 		# reversed from V54000
 		# V54003 now asks whether or not to retain .o files if libgtmutil.so is created
 		# We answer "y" to this question
-		# If libgtmutil.so is not created(on i686) this question is not asked
+		# If libgtmutil.so is not created(on i586) this question is not asked
 		if("$osname" != "osf1") then
-			if ("$osname" == "linux" && "$arch" == "i686") then
+			if ("$osname" == "linux" && "$arch" == "i586") then
 	 			sh ./configure << CONFIGURE_EOF
 
 $rootgroup
@@ -528,7 +528,7 @@ CONFIGURE_EOF
 				set comp="$gtm_tools/gtm_compare_dir.csh ${install} ${tmp_dist}/$defgroup $gtm_tools/bdelete.txt"
 				set adddir=$gtm_tools/badd.txt
 				set deldir=$gtm_tools/bdeldir.txt
-				if (("linux" == ${osname}) && ("i686" == ${arch})) then
+				if (("linux" == ${osname}) && ("i586" == ${arch})) then
 					set adddir=$gtm_tools/linuxi686_badd.txt
 				else if (("hpux" == ${osname}) && ("parisc" == ${arch})) then
 					set adddir=$gtm_tools/hpuxparisc_badd.txt
diff --git a/sr_unix/libmupip.list b/sr_unix/libmupip.list
index 1b5b823..1d501d9 100644
--- a/sr_unix/libmupip.list
+++ b/sr_unix/libmupip.list
@@ -89,6 +89,7 @@ mu_replpool_grab_sem
 mu_replpool_release_sem
 mu_rndwn_all
 mu_rndwn_file
+mu_rndwn_rlnkctl
 mu_rndwn_repl_instance
 mu_rndwn_replpool
 mu_signal_process
@@ -128,6 +129,7 @@ mupip_help
 mupip_integ
 mupip_intrpt
 mupip_quit
+mupip_rctldump
 mupip_recover
 mupip_reorg
 mupip_restore
@@ -204,6 +206,7 @@ ss_anal_shdw_file
 ss_get_block
 ss_initiate
 ss_read_block
+trigger_upgrade
 upd_log_init
 updhelper_end
 updhelper_init
diff --git a/sr_unix/load.h b/sr_unix/load.h
index bc34fb7..fb8bd14 100644
--- a/sr_unix/load.h
+++ b/sr_unix/load.h
@@ -33,8 +33,8 @@
 	continue; /* continue, when (onerror = ONERROR_PROCEED) or when user selects Yes in ONERROR_INTERACTIVE */		\
 }
 
-void bin_load(uint4 begin, uint4 end);
-void go_load(uint4 begin, uint4 end);
+void bin_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len);
+void go_load(uint4 begin, uint4 end, char *line1_ptr, int line1_len, char *line2_ptr, int line2_len);
 void goq_load(void);
 
 #endif /* LOAD_INCLUDED */
diff --git a/sr_unix/m_zrupdate.c b/sr_unix/m_zrupdate.c
index d65f7ec..6d1d5e8 100644
--- a/sr_unix/m_zrupdate.c
+++ b/sr_unix/m_zrupdate.c
@@ -19,7 +19,7 @@
 #include "advancewindow.h"
 #include "cmd.h"
 
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 /* Routine to compile ZRUPDATE command
  *
  * Current syntax:
diff --git a/sr_unix/maskpass.c b/sr_unix/maskpass.c
index 33e5817..c125765 100644
--- a/sr_unix/maskpass.c
+++ b/sr_unix/maskpass.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2009, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2009, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -17,16 +17,24 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <signal.h>
+#include <termios.h>
 
 #include "gtmxc_types.h"
 
 #include "gtmcrypt_util.h"
 
+static struct termios *tty = NULL;
+
+void maskpass_signal_handler(int sig);
+
 int main()
 {
-	char		passwd[GTM_PASSPHRASE_MAX], hex_out[GTM_PASSPHRASE_MAX * 2], mumps_exe[GTM_PATH_MAX], *env_ptr;
-	struct stat	stat_info;
-	gtm_string_t	passwd_str;
+	char			passwd[GTM_PASSPHRASE_MAX], hex_out[GTM_PASSPHRASE_MAX * 2], mumps_exe[GTM_PATH_MAX], *env_ptr;
+	struct stat		stat_info;
+	gtm_string_t		passwd_str;
+	struct sigaction	reset_term_handler, ignore_handler;
+	int			sig;
 
 	/* Since the obfuscated password depends on $USER and the inode of $gtm_dist/mumps, make sure all the pre-requisites are
 	 * available to this process.
@@ -47,8 +55,38 @@ int main()
 		printf("Cannot stat %s\n", mumps_exe);
 		exit(EXIT_FAILURE);
 	}
+	/* We want the process to restore the terminal settings (if they already changed by the time a signal is caught) on the more
+	 * conventional terminal signals, such as SIGINT and SIGTERM, and ignore the non-critical other ones. We also do not want to
+	 * allow putting the process in the background because the terminal settings may be unsuitable for user interaction at that
+	 * point, and the user may decide to "sanitize" them, which might render the entered password visible upon resumption.
+	 */
+	reset_term_handler.sa_handler = maskpass_signal_handler;
+	reset_term_handler.sa_flags = 0;
+	sigfillset(&reset_term_handler.sa_mask);
+	ignore_handler.sa_handler = SIG_IGN;
+	ignore_handler.sa_flags = 0;
+	sigemptyset(&ignore_handler.sa_mask);
+	for (sig = 1; sig <= NSIG; sig++)
+	{
+		switch (sig)
+		{
+			case SIGINT:
+			case SIGTERM:
+				sigaction(sig, &reset_term_handler, NULL);
+				break;
+			case SIGSEGV:
+			case SIGABRT:
+			case SIGBUS:
+			case SIGFPE:
+			case SIGTRAP:
+			case SIGKILL:
+				break;
+			default:
+				sigaction(sig, &ignore_handler, NULL);
+		}
+	}
 	/* Read the password (with terminal echo turned off). */
-	if (-1 == gc_read_passwd(GTMCRYPT_DEFAULT_PASSWD_PROMPT, passwd, GTM_PASSPHRASE_MAX))
+	if (-1 == gc_read_passwd(GTMCRYPT_DEFAULT_PASSWD_PROMPT, passwd, GTM_PASSPHRASE_MAX, &tty))
 	{
 		printf("%s\n", gtmcrypt_err_string);
 		exit(EXIT_FAILURE);
@@ -66,3 +104,12 @@ int main()
 	printf("%s\n", hex_out);
 	return 0;
 }
+
+void maskpass_signal_handler(int sig)
+{	/* If gc_read_passwd() changed the terminal settings before we got hit by an interrupt, the original terminal state should
+	 * have been saved in tty, so we will only restore the terminal settings when the pointer is non-NULL.
+	 */
+	if (NULL != tty)
+		tcsetattr(fileno(stdin), TCSAFLUSH, tty);
+	exit(-1);
+}
diff --git a/sr_unix/mdefsp.h b/sr_unix/mdefsp.h
index 4311150..27e30f9 100644
--- a/sr_unix/mdefsp.h
+++ b/sr_unix/mdefsp.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *                                                              *
- *    Copyright 2001, 2013 Fidelity Information Services, Inc   *
+ *    Copyright 2001, 2014 Fidelity Information Services, Inc   *
  *                                                              *
  *    This source code contains the intellectual property       *
  *    of its copyright holder(s), and is made available         *
@@ -14,13 +14,14 @@
 
 #include <sys/types.h>
 
-#ifdef GTM64
-typedef	long		int8;		/* 8-byte signed integer */
-typedef unsigned long	uint8;	  	/* 8-byte unsigned integer */
-typedef unsigned long 	gtm_uint8;	/*these two datatypes are defined because */
-typedef		 long	gtm_int8;	/*int8 and uint8 are system defined in AIX_64*/
-#define INT8_NATIVE
+/* All current Unix platforms support {u,}int64_t, so set these up regardless of GTM64 setting. */
+#ifndef int8
+typedef	int64_t		int8;		/* 8-byte signed integer */
+typedef uint64_t	uint8;	  	/* 8-byte unsigned integer */
 #endif
+typedef uint64_t 	gtm_uint8;	/* these two datatypes are defined because */
+typedef	int64_t		gtm_int8;	/* int8 and uint8 are system defined in AIX_64 */
+#define INT8_NATIVE
 
 #ifdef __s390__
 typedef		 short int2;		/* 2-byte signed integer */
@@ -42,6 +43,7 @@ typedef uint2 mach_inst;
 #ifdef __sparc
 #define CACHELINE_SIZE	256
 #define USHBIN_SUPPORTED
+#define AUTORELINK_SUPPORTED
 #define LINKAGE_PSECT_BOUNDARY	8
 #define OFF_T_LONG
 #define INO_T_LONG
@@ -71,6 +73,9 @@ typedef uint4 mach_inst;
 #define MUTEX_MSEM_WAKE
 #define POSIX_MSEM
 #define USHBIN_SUPPORTED
+/* #define AUTORELINK_SUPPORTED -- not yet due to issues with replacing mapped object files - revisit if/when support objects in
+ * shared memory.
+ */
 #define OFF_T_LONG
 /* Make sure linkage Psect is aligned on appropriate boundary. */
 #ifdef __ia64
@@ -126,7 +131,8 @@ typedef unsigned short	in_port_t;
 #  ifdef __linux__
 #    undef BIGENDIAN
 #    define USHBIN_SUPPORTED
-     /* Make sure linkage Psect is aligned on appropriate boundary. */
+#    define AUTORELINK_SUPPORTED /* If this ever comes back */
+     /* Make sure linkage Psect is aligned on appropriate boundary */
 #    define LINKAGE_PSECT_BOUNDARY  8
 typedef uint4 mach_inst;	/* machine instruction */
 #  elif defined(__hpux)
@@ -146,6 +152,7 @@ typedef char  mach_inst;	/* machine instruction */
 #ifdef __x86_64__
 #define CACHELINE_SIZE	64
 #define USHBIN_SUPPORTED
+#define AUTORELINK_SUPPORTED
 #define INO_T_LONG
 /*
 #define MUTEX_MSEM_WAKE
diff --git a/sr_unix/mmrhash.c b/sr_unix/mmrhash.c
index 5894cf5..5dd991d 100644
--- a/sr_unix/mmrhash.c
+++ b/sr_unix/mmrhash.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *                                                              *
- *      Copyright 2011 Fidelity Information Services, Inc       *
+ *      Copyright 2011, 2014 Fidelity Information Services, Inc       *
  *                                                              *
  *      This source code contains the intellectual property     *
  *      of its copyright holder(s), and is made available       *
@@ -22,6 +22,9 @@
  *-----------------------------------------------------------------------------*/
 
 #include "mdef.h"
+
+#include "gtm_string.h"
+
 #include "mmrhash.h"
 
 /*
@@ -44,35 +47,34 @@
 #endif
 
 
-static uint4 rotl32 ( uint4 x, char r );
 static uint4 fmix ( uint4 h );
 
-#ifdef GTM64
-static gtm_uint8 rotl64 ( gtm_uint8 x, char r );
 static gtm_uint8 fmix64 ( gtm_uint8 k );
-#endif
-
-static uint4 rotl32 ( uint4 x, char r )
-{
-  return (x << r) | (x >> (32 - r));
-}
 
-#ifdef GTM64
-static gtm_uint8 rotl64 ( gtm_uint8 x, char r )
-{
-  return (x << r) | (x >> (64 - r));
-}
-#endif
-
-#define	ROTL32(x,y)	rotl32(x,y)
-#define ROTL64(x,y)	rotl64(x,y)
+#define ROTL32(X,Y)	(((X) << (Y)) | ((X) >> (32 - (Y))))
+#define ROTL64(X,Y)	(((X) << (Y)) | ((X) >> (64 - (Y))))
 
 #define BIG_CONSTANT(x) (x##LLU)
 
 #define GETBLOCK(p,i) (((const uint4 *)p)[(int)i])
 
-#ifdef GTM64
 #define GETBLOCK64(p,i) (((const gtm_uint8 *)p)[(int)i])
+
+#ifdef BIGENDIAN
+#	if defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3))
+#	define UI64_TO_LE(X) (__builtin_bswap64(*((uint64_t*)&(X))))
+#	else
+#	define UI64_TO_LE(X) (X) = ((((X) & BIG_CONSTANT(0xff)) << 56)								\
+					| (((X) & BIG_CONSTANT(0xff00)) << 40)							\
+					| (((X) & BIG_CONSTANT(0xff0000)) << 24)						\
+					| (((X) & BIG_CONSTANT(0xff000000)) << 8)						\
+					| (((X) & BIG_CONSTANT(0xff00000000)) >> 8)						\
+					| (((X) & BIG_CONSTANT(0xff0000000000)) >> 24)						\
+					| (((X) & BIG_CONSTANT(0xff000000000000)) >> 40)					\
+					| (((X) & BIG_CONSTANT(0xff00000000000000)) >> 56))
+#	endif
+#else
+#define UI64_TO_LE(X)			/* nothing */
 #endif
 
 /*-----------------------------------------------------------------------------
@@ -91,7 +93,6 @@ static FORCE_INLINE uint4 fmix ( uint4 h )
 
 /*----------*/
 
-#ifdef GTM64
 static FORCE_INLINE gtm_uint8 fmix64 ( gtm_uint8 k )
 {
   k ^= k >> 33;
@@ -102,7 +103,6 @@ static FORCE_INLINE gtm_uint8 fmix64 ( gtm_uint8 k )
 
   return k;
 }
-#endif
 
 /*-----------------------------------------------------------------------------*/
 
@@ -110,10 +110,11 @@ void MurmurHash3_x86_32 ( const void * key, int len,
                           uint4 seed, void * out )
 {
   int i;
-  const unsigned char * data = (const unsigned char*)key;
   const unsigned char * tail;
   const uint4 * blocks;
   const int nblocks = len / 4;
+  static char	*buff;
+  static int	bufflen;
 
   uint4 h1 = seed;
 
@@ -123,9 +124,28 @@ void MurmurHash3_x86_32 ( const void * key, int len,
 
   /*----------
    * body   */
-
-  blocks = (const uint4 *)(data + nblocks*4);
-
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+  /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+   * messages from an architecture that does not support it.
+   */
+  if (len && (0 != ((UINTPTR_T)key % 4)))
+  {	/* make buffer 4-byte aligned */
+  	if (bufflen < len)
+	{
+  		if (NULL != buff)
+		{
+			assert(bufflen);
+			free(buff);
+		}
+		bufflen = len * 2;
+		buff = malloc(bufflen);
+	}
+	assert(bufflen >= len);
+	memcpy(buff, key, len);
+	key = (const unsigned char*)buff;
+  }
+# endif
+  blocks = (const uint4 *)((char *)key + nblocks*4);
   for(i = -nblocks; i; i++)
   {
     k1 = GETBLOCK(blocks,i);
@@ -142,10 +162,14 @@ void MurmurHash3_x86_32 ( const void * key, int len,
   /*----------
    * tail   */
 
-  tail = (const unsigned char*)(data + nblocks*4);
+  tail = (const unsigned char*)blocks;
 
   k1 = 0;
 
+  /* The shifts below assume little endian, so the handling of the tail block is inconsistent with normal blocks
+   * on big endian systems. However, we are already using this version and we don't want to change the resulting
+   * hashes, so leave it alone.
+   */
   switch(len & 3)
   {
   case 3: k1 ^= tail[2] << 16;
@@ -173,6 +197,8 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
   const unsigned char * data = (const unsigned char*)key;
   const unsigned char * tail;
   const int nblocks = len / 16;
+  static char	*buff;
+  static int	bufflen;
 
   uint4 h1 = seed;
   uint4 h2 = seed;
@@ -191,6 +217,27 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
 
   /*----------
    * body   */
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+  /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+   * messages from an architecture that does not support it.
+   */
+  if (len && (0 != ((UINTPTR_T)key % 4)))
+  {	/* make buffer 4-byte aligned */
+  	if (bufflen < len)
+	{
+  		if (NULL != buff)
+		{
+			assert(bufflen);
+			free(buff);
+		}
+		bufflen = len * 2;
+		buff = malloc(bufflen);
+	}
+	assert(bufflen >= len);
+	memcpy(buff, key, len);
+	data = (const unsigned char*)buff;
+  }
+# endif
 
   const uint4 * blocks = (const uint4 *)(data + nblocks*16);
 
@@ -228,6 +275,9 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
   k3 = 0;
   k4 = 0;
 
+  /* The shifts below assume little endian, so the handling of the tail block is inconsistent with normal blocks
+   * on big endian systems. If we start using this routine, we should decide whether to fix it or not.
+   */
   switch(len & 15)
   {
   case 15: k4 ^= tail[14] << 16;
@@ -278,7 +328,6 @@ void MurmurHash3_x86_128 ( const void * key, const int len,
 
 /*-----------------------------------------------------------------------------*/
 
-#ifdef GTM64
 void MurmurHash3_x64_128 ( const void * key, const int len,
                            const uint4 seed, void * out )
 {
@@ -286,6 +335,8 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
   const unsigned char * data = (const unsigned char*)key;
   const unsigned char * tail;
   const int nblocks = len / 16;
+  static char	*buff;
+  static int	bufflen;
 
   gtm_uint8 h1 = seed;
   gtm_uint8 h2 = seed;
@@ -298,6 +349,27 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
 
   /*----------
    * body   */
+# ifndef UNALIGNED_ACCESS_SUPPORTED
+  /* Murmur3 hash works only on 4-byte aligned keys so align key to avoid unaligned access error
+   * messages from an architecture that does not support it.
+   */
+  if (len && (0 != ((UINTPTR_T)key % 8)))
+  {	/* make buffer 4-byte aligned */
+  	if (bufflen < len)
+	{
+  		if (NULL != buff)
+		{
+			assert(bufflen);
+			free(buff);
+		}
+		bufflen = len * 2;
+		buff = malloc(bufflen);
+	}
+	assert(bufflen >= len);
+	memcpy(buff, key, len);
+	data = (const unsigned char*)buff;
+  }
+# endif
 
   const gtm_uint8 * blocks = (const gtm_uint8 *)(data);
 
@@ -306,6 +378,9 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
     k1 = GETBLOCK64(blocks,i*2+0);
     k2 = GETBLOCK64(blocks,i*2+1);
 
+    UI64_TO_LE(k1);
+    UI64_TO_LE(k2);
+
     k1 *= c1; k1  = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
 
     h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
@@ -323,6 +398,10 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
   k1 = 0;
   k2 = 0;
 
+  /* The shifts below originally assumed little endian, so the handling of the tail block was inconsistent with normal blocks
+   * on big endian systems. Since we haven't used this routine previously, fix it here instead of making the progressive
+   * version consistent with the broken implementation.
+   */
   switch(len & 15)
   {
   case 15: k2 ^= ((gtm_uint8)tail[14]) << 48;
@@ -362,7 +441,372 @@ void MurmurHash3_x64_128 ( const void * key, const int len,
   ((gtm_uint8*)out)[0] = h1;
   ((gtm_uint8*)out)[1] = h2;
 }
+
+/*******************************************************************************
+ * Progressive 128-bit MurmurHash3
+ *******************************************************************************/
+
+#define C1 BIG_CONSTANT(0x87c37b91114253d5)
+#define C2 BIG_CONSTANT(0x4cf5ad432745937f)
+#define M1 0x52dce729
+#define M2 0x38495ab5
+
+#define LSHIFT_BYTES_SAFE(LHS, RHS)	((LHS) << ((RHS) * 8))
+#define RSHIFT_BYTES_SAFE(LHS, RHS)	((LHS) >> ((RHS) * 8))
+#define LSHIFT_BYTES(LHS, RHS)		((RHS < SIZEOF(LHS)) ? LSHIFT_BYTES_SAFE(LHS, RHS) : 0)
+#define RSHIFT_BYTES(LHS, RHS)		((RHS < SIZEOF(LHS)) ? RSHIFT_BYTES_SAFE(LHS, RHS) : 0)
+
+#if !defined(BIGENDIAN)
+
+/* Little Endian */
+
+#define ADD_BYTES(STATEPTR, KEY, COUNT)										\
+MBSTART {													\
+	int			ab_count, ab_offset, ab_carry_bytes;						\
+	const unsigned char	*ab_key, *ab_ptr;								\
+	gtm_uint8		c1, c2;										\
+														\
+	assert((STATEPTR)->carry_bytes + (COUNT) >= 0);								\
+	assert((STATEPTR)->carry_bytes + (COUNT) <= 16);							\
+	ab_count = (COUNT);											\
+	ab_carry_bytes = (STATEPTR)->carry_bytes;								\
+	ab_offset = ab_carry_bytes + ab_count;									\
+	ab_key = (KEY);												\
+	ab_ptr = ab_key + ab_count - 1;										\
+	c1 = (STATEPTR)->c.one;											\
+	c2 = (STATEPTR)->c.two;											\
+	assert((ab_carry_bytes != 0) || ((c1 == 0) && (c2 == 0)));						\
+	for (; (ab_offset > 8) && (ab_ptr >= ab_key); ab_ptr--, ab_offset--)					\
+		c2 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (ab_offset - 9));					\
+	for (; ab_ptr >= ab_key; ab_ptr--, ab_offset--)								\
+		c1 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (ab_offset - 1));					\
+	assert(((ab_carry_bytes + ab_count) != 0) || ((c1 == 0) && (c2 == 0)));					\
+	assert((ab_count != 0) || (((STATEPTR)->c.one == c1) && ((STATEPTR)->c.two == c2)));			\
+	(STATEPTR)->c.one = c1;											\
+	(STATEPTR)->c.two = c2;											\
+	(STATEPTR)->carry_bytes = ab_carry_bytes + ab_count;							\
+} MBEND
+
+#define GET_BLOCK(STATEPTR, KEY, K1, K2)									\
+MBSTART {													\
+	int		gb_carry_bytes;										\
+	gtm_uint8	gb_m1, gb_m2, gb_k1, gb_k2, gb_c1, gb_c2;						\
+														\
+	assert(((STATEPTR)->carry_bytes != 0) || (((STATEPTR)->c.one == 0) && ((STATEPTR)->c.two == 0)));	\
+	assert((STATEPTR)->carry_bytes < 16);									\
+	gb_carry_bytes = (STATEPTR)->carry_bytes;								\
+	gb_m1 = ((gtm_uint8 *)(KEY))[0];									\
+	gb_m2 = ((gtm_uint8 *)(KEY))[1];									\
+	if (0 == gb_carry_bytes)										\
+	{													\
+		(K1) = gb_m1;											\
+		(K2) = gb_m2;											\
+	}													\
+	else if (8 == gb_carry_bytes)										\
+	{													\
+		gb_k1 = (STATEPTR)->c.one;									\
+		gb_k2 = gb_m1;											\
+		gb_c1 = gb_m2; 											\
+		/* gb_c2 = 0; */										\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		assert(0 == (STATEPTR)->c.two);									\
+	}													\
+	else if (gb_carry_bytes < 8)										\
+	{													\
+		gb_k1 = (STATEPTR)->c.one | LSHIFT_BYTES_SAFE(gb_m1, gb_carry_bytes);				\
+		gb_k2 = RSHIFT_BYTES_SAFE(gb_m1, (8 - gb_carry_bytes))				 		\
+			| LSHIFT_BYTES_SAFE(gb_m2, gb_carry_bytes);						\
+		gb_c1 = RSHIFT_BYTES_SAFE(gb_m2, (8 - gb_carry_bytes));						\
+		/* gb_c2 = 0; */										\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		assert(0 == (STATEPTR)->c.two);									\
+	}													\
+	else {													\
+		gb_k1 = (STATEPTR)->c.one;									\
+		gb_k2 = (STATEPTR)->c.two									\
+			| LSHIFT_BYTES_SAFE(gb_m1, (gb_carry_bytes - 8));					\
+		gb_c1 = RSHIFT_BYTES_SAFE(gb_m1, (16 - gb_carry_bytes))						\
+			| LSHIFT_BYTES_SAFE(gb_m2, (gb_carry_bytes - 8));					\
+		gb_c2 = RSHIFT_BYTES_SAFE(gb_m2, (16 - gb_carry_bytes));					\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		(STATEPTR)->c.two = gb_c2;									\
+	}													\
+} MBEND
+
+#else
+
+/* Big Endian */
+
+#define ADD_BYTES(STATEPTR, KEY, COUNT)										\
+MBSTART {													\
+	int			ab_count, ab_offset, ab_carry_bytes;						\
+	const unsigned char	*ab_key, *ab_ptr;								\
+	gtm_uint8		c1, c2;										\
+														\
+	assert((STATEPTR)->carry_bytes + (COUNT) >= 0);								\
+	assert((STATEPTR)->carry_bytes + (COUNT) <= 16);							\
+	ab_count = (COUNT);											\
+	ab_carry_bytes = (STATEPTR)->carry_bytes;								\
+	ab_offset = ab_carry_bytes + ab_count;									\
+	ab_key = (KEY);												\
+	ab_ptr = ab_key + ab_count - 1;										\
+	c1 = (STATEPTR)->c.one;											\
+	c2 = (STATEPTR)->c.two;											\
+	assert((ab_carry_bytes != 0) || ((c1 == 0) && (c2 == 0)));						\
+	for (; (ab_offset > 8) && (ab_ptr >= ab_key); ab_ptr--, ab_offset--)					\
+		c2 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (16 - ab_offset));					\
+	for (; ab_ptr >= ab_key; ab_ptr--, ab_offset--)								\
+		c1 |= LSHIFT_BYTES_SAFE((gtm_uint8)*ab_ptr, (8 - ab_offset));					\
+	assert(((ab_carry_bytes + ab_count) != 0) || ((c1 == 0) && (c2 == 0)));					\
+	assert((ab_count != 0) || (((STATEPTR)->c.one == c1) && ((STATEPTR)->c.two == c2)));			\
+	(STATEPTR)->c.one = c1;											\
+	(STATEPTR)->c.two = c2;											\
+	(STATEPTR)->carry_bytes = ab_carry_bytes + ab_count;							\
+} MBEND
+
+#define GET_BLOCK(STATEPTR, KEY, K1, K2)									\
+MBSTART {													\
+	int		gb_carry_bytes;										\
+	gtm_uint8	gb_m1, gb_m2, gb_k1, gb_k2, gb_c1, gb_c2;						\
+														\
+	assert(((STATEPTR)->carry_bytes != 0) || (((STATEPTR)->c.one == 0) && ((STATEPTR)->c.two == 0)));	\
+	gb_carry_bytes = (STATEPTR)->carry_bytes;								\
+	gb_m1 = ((gtm_uint8 *)(KEY))[0];									\
+	gb_m2 = ((gtm_uint8 *)(KEY))[1];									\
+	if (0 == gb_carry_bytes)										\
+	{													\
+		(K1) = gb_m1;											\
+		(K2) = gb_m2;											\
+	}													\
+	else if (8 == gb_carry_bytes)										\
+	{													\
+		gb_k1 = (STATEPTR)->c.one;									\
+		gb_k2 = gb_m1;									 		\
+		gb_c1 = gb_m2;											\
+		/* gb_c2 = 0; */										\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		assert(0 == (STATEPTR)->c.two);									\
+	}													\
+	else if ( gb_carry_bytes < 8)										\
+	{													\
+		gb_k1 = (STATEPTR)->c.one | RSHIFT_BYTES_SAFE(gb_m1, gb_carry_bytes);				\
+		gb_k2 = LSHIFT_BYTES_SAFE(gb_m1, (8 - gb_carry_bytes))				 		\
+			| RSHIFT_BYTES_SAFE(gb_m2, gb_carry_bytes);						\
+		gb_c1 = LSHIFT_BYTES_SAFE(gb_m2, (8 - gb_carry_bytes));						\
+		/* gb_c2 = 0; */										\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		assert(0 == (STATEPTR)->c.two);									\
+	}													\
+	else {													\
+		gb_k1 = (STATEPTR)->c.one;									\
+		gb_k2 = (STATEPTR)->c.two									\
+			| RSHIFT_BYTES_SAFE(gb_m1, (gb_carry_bytes - 8));					\
+		gb_c1 = LSHIFT_BYTES_SAFE(gb_m1, (16 - gb_carry_bytes))						\
+			| RSHIFT_BYTES_SAFE(gb_m2, (gb_carry_bytes - 8));					\
+		gb_c2 = LSHIFT_BYTES_SAFE(gb_m2, (16 - gb_carry_bytes));					\
+		(K1) = gb_k1;											\
+		(K2) = gb_k2;											\
+		(STATEPTR)->c.one = gb_c1;									\
+		(STATEPTR)->c.two = gb_c2;									\
+	}													\
+} MBEND
+
 #endif
 
+#define INTEGRATE_K1(K1, H1)											\
+MBSTART {													\
+	(K1) *= C1;												\
+	(K1) = ROTL64((K1), 31);										\
+	(K1) *= C2;												\
+	(H1) ^= (K1);												\
+} MBEND
+
+#define INTEGRATE_K2(K2, H2)											\
+MBSTART {													\
+	(K2) *= C2;												\
+	(K2) = ROTL64((K2), 33);										\
+	(K2) *= C1;												\
+	(H2) ^= (K2);												\
+} MBEND
+
+#define PROCESS_BLOCK(K1, K2, H1, H2)										\
+MBSTART {													\
+	UI64_TO_LE(K1);												\
+	UI64_TO_LE(K2);												\
+	INTEGRATE_K1(K1, H1);											\
+	(H1) = ROTL64((H1), 27);										\
+	(H1) += (H2);												\
+	(H1) = (H1) * 5 + M1;											\
+	INTEGRATE_K2(K2, H2);											\
+	(H2) = ROTL64((H2), 31);										\
+	(H2) += (H1);												\
+	(H2) = (H2) * 5 + M2;											\
+} MBEND
+
+#define PROCESS_BYTES(STATEPTR, KEY, LEN)									\
+MBSTART {													\
+	int pb_carry_fill = 0;											\
+														\
+	assert((LEN) < 16);											\
+	if ((STATEPTR)->carry_bytes + (LEN) >= 16)								\
+	{													\
+		/* fill the carry field, process it as a block, then clear it */				\
+		pb_carry_fill = 16 - (STATEPTR)->carry_bytes;							\
+		ADD_BYTES((STATEPTR), (KEY), pb_carry_fill);							\
+		assert((STATEPTR)->carry_bytes == 16);								\
+		PROCESS_BLOCK((STATEPTR)->c.one, (STATEPTR)->c.two, (STATEPTR)->h.one, (STATEPTR)->h.two);	\
+		(STATEPTR)->c.one = (STATEPTR)->c.two = 0;							\
+		(STATEPTR)->carry_bytes = 0;									\
+	}													\
+	ADD_BYTES((STATEPTR), (KEY) + pb_carry_fill, (LEN) - pb_carry_fill);					\
+} MBEND
+
+#define UNALIGNED_SAFE	(defined(__i386) || defined(__x86_64__) || defined(_AIX))
+
+/* This is an endian-independent 16-byte murmur hash function */
+void gtmmrhash_128(const void *key, int len, uint4 seed, gtm_uint16 *out)
+{
+	hash128_state_t state;
+
+	HASH128_STATE_INIT(state, seed);
+	assert((state.carry_bytes == 0) && (state.c.one == 0) && (state.c.two == 0));
+	gtmmrhash_128_ingest(&state, key, len);
+	gtmmrhash_128_result(&state, len, out);
+}
+
+/* This is the same as gtmmrhash_128 (i.e. is endian independent) except that it generates a 4-byte hash
+ * (needed e.g. by STR_HASH macro). To avoid the overhead of an extra function call, we duplicate the
+ * code of "gtmmmrhash_128" here.
+ */
+void gtmmrhash_32(const void *key, int len, uint4 seed, uint4 *out4)
+{
+	hash128_state_t state;
+	gtm_uint16	out16;
+
+	HASH128_STATE_INIT(state, seed);
+	assert((state.carry_bytes == 0) && (state.c.one == 0) && (state.c.two == 0));
+	gtmmrhash_128_ingest(&state, key, len);
+	gtmmrhash_128_result(&state, len, &out16);
+	*out4 = (uint4)out16.one;
+}
+
+void gtmmrhash_128_ingest(hash128_state_t *state, const void *key, int len)
+{
+	int			i;
+	gtm_uint8		k1, k2;
+	const unsigned char	*keyptr;
+
+	if (0 == len)
+		return;
+
+	keyptr = key;
+#	if !UNALIGNED_SAFE
+	/* determine the number of bytes to consume to reach 64-bit (8 byte) alignment */
+	i = (0x8 - ((UINTPTR_T)keyptr & 0x7)) & 0x7;
+	if (i > len)
+		i = len;
+	if (i > 0)
+	{
+		PROCESS_BYTES(state, keyptr, i);
+		keyptr += i;
+		len -= i;
+	}
+#	endif
+	for (; len >= 16; len -= 16, keyptr += 16)
+	{
+		GET_BLOCK(state, keyptr, k1, k2);
+		PROCESS_BLOCK(k1, k2, state->h.one, state->h.two);
+	}
+	if (len > 0)
+		PROCESS_BYTES(state, keyptr, len);
+}
+
+void gtmmrhash_128_result(hash128_state_t *state, uint4 total_len, gtm_uint16 *out)
+{
+	gtm_uint8		k1, k2, h1, h2;
+
+	k1 = state->c.one;
+	k2 = state->c.two;
+	h1 = state->h.one;
+	h2 = state->h.two;
+
+	UI64_TO_LE(k1);
+	UI64_TO_LE(k2);
+	if (state->carry_bytes != 0)
+	{
+		if (state->carry_bytes > 8)
+		{
+			INTEGRATE_K2(k2, h2);
+		}
+		INTEGRATE_K1(k1, h1);
+	}
+
+	h1 ^= total_len;
+	h2 ^= total_len;
+	h1 += h2;
+	h2 += h1;
+	h1 = fmix64(h1);
+	h2 = fmix64(h2);
+	h1 += h2;
+	h2 += h1;
+
+	out->one = h1;
+	out->two = h2;
+}
+
+void gtmmrhash_128_bytes(const gtm_uint16 *hash, unsigned char *out)
+{
+#	ifdef BIGENDIAN
+#	define EXTRACT_BYTE(X, N)	(((uint64_t)(X) & ((uint64_t)0xff << (N) * 8)) >> (N) * 8)
+	out[0] = EXTRACT_BYTE(hash->one, 0);
+	out[1] = EXTRACT_BYTE(hash->one, 1);
+	out[2] = EXTRACT_BYTE(hash->one, 2);
+	out[3] = EXTRACT_BYTE(hash->one, 3);
+	out[4] = EXTRACT_BYTE(hash->one, 4);
+	out[5] = EXTRACT_BYTE(hash->one, 5);
+	out[6] = EXTRACT_BYTE(hash->one, 6);
+	out[7] = EXTRACT_BYTE(hash->one, 7);
+	out[8] = EXTRACT_BYTE(hash->two, 0);
+	out[9] = EXTRACT_BYTE(hash->two, 1);
+	out[10] = EXTRACT_BYTE(hash->two, 2);
+	out[11] = EXTRACT_BYTE(hash->two, 3);
+	out[12] = EXTRACT_BYTE(hash->two, 4);
+	out[13] = EXTRACT_BYTE(hash->two, 5);
+	out[14] = EXTRACT_BYTE(hash->two, 6);
+	out[15] = EXTRACT_BYTE(hash->two, 7);
+#	else
+	((gtm_uint8 *)out)[0] = hash->one;
+	((gtm_uint8 *)out)[1] = hash->two;
+#	endif
+}
+
+void gtmmrhash_128_hex(const gtm_uint16 *hash, unsigned char *out)
+{
+	int			i;
+	unsigned char		bytes[16], n;
+
+	gtmmrhash_128_bytes(hash, bytes);
+	for (i = 0; i < 16; i++)
+	{
+		n = bytes[i] & 0xf;
+		out[i * 2 + 1] = (n < 10) ? (n + '0') : (n - 10 + 'a');
+		n = (bytes[i] >> 4) & 0xf;
+		out[i * 2] = (n < 10) ? (n + '0') : (n - 10 + 'a');
+	}
+}
+
+
+/*******************************************************************************/
+
 /*-----------------------------------------------------------------------------*/
 
diff --git a/sr_unix/mmrhash.h b/sr_unix/mmrhash.h
index ed193da..052a4f5 100644
--- a/sr_unix/mmrhash.h
+++ b/sr_unix/mmrhash.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *                                                              *
- *      Copyright 2011 Fidelity Information Services, Inc       *
+ *      Copyright 2011, 2014 Fidelity Information Services, Inc       *
  *                                                              *
  *      This source code contains the intellectual property     *
  *      of its copyright holder(s), and is made available       *
@@ -26,9 +26,33 @@ void MurmurHash3_x86_32  ( const void * key, int len, uint4 seed, void * out );
 
 void MurmurHash3_x86_128 ( const void * key, int len, uint4 seed, void * out );
 
-#ifdef GTM64
 void MurmurHash3_x64_128 ( const void * key, int len, uint4 seed, void * out );
-#endif
+
+typedef struct
+{
+	gtm_uint8	one, two;
+} gtm_uint16;
+
+typedef struct
+{
+	gtm_uint16	h, c;
+	int		carry_bytes;
+} hash128_state_t;
+
+#define HASH128_STATE_INIT(STATE, SEED)							\
+MBSTART {										\
+	(STATE).h.one = (STATE).h.two = (SEED);						\
+	(STATE).c.one = (STATE).c.two = 0;						\
+	(STATE).carry_bytes = 0;							\
+} MBEND
+
+void gtmmrhash_128(const void *key, int len, uint4 seed, gtm_uint16 *out);
+void gtmmrhash_32(const void *key, int len, uint4 seed, uint4 *out4);
+void gtmmrhash_128_ingest(hash128_state_t *state, const void *key, int len);
+void gtmmrhash_128_result(hash128_state_t *state, uint4 total_len, gtm_uint16 *out);
+
+void gtmmrhash_128_hex(const gtm_uint16 *hash, unsigned char *out);
+void gtmmrhash_128_bytes(const gtm_uint16 *hash, unsigned char *out);
 
 #endif
 
diff --git a/sr_unix/mu_all_version_standalone.c b/sr_unix/mu_all_version_standalone.c
index 6af0afa..511fe28 100644
--- a/sr_unix/mu_all_version_standalone.c
+++ b/sr_unix/mu_all_version_standalone.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -92,7 +92,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 		{
 			save_errno = errno;
 			mu_all_version_release_standalone(sem_inf);
-			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("ftok()"), CALLFROM, save_errno);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("ftok()"), CALLFROM, save_errno);
 		}
 		sem_inf[i].sem_id = semget(sem_inf[i].ftok_key, 3, RWDALL | IPC_CREAT | IPC_EXCL);
 		if (-1 == sem_inf[i].sem_id)
@@ -107,11 +107,13 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 			*/
 			if (EEXIST == save_errno || EAGAIN == save_errno || EINVAL == save_errno)
 				/* Semaphore already exists and/or is locked-- likely rundown needed */
-				rts_error(VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
-						save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9)
+					MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+					save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
 			else
-				rts_error(VARLSTCNT(12) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno, 0,
-						ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12)
+					ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno, 0,
+					ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
 		}
 		SEMOP(sem_inf[i].sem_id, sop, 4, rc, NO_WAIT);
 		if (-1 == rc)
@@ -119,15 +121,16 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 			save_errno = errno;
 			mu_all_version_release_standalone(sem_inf);
 			if (EAGAIN == save_errno)
-				rts_error(VARLSTCNT(12) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12)
+					MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
 						save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key,
-						ERR_SEMID, 1, sem_inf[i].sem_id);
+					ERR_SEMID, 1, sem_inf[i].sem_id);
 			else
-				rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno, 0,
-						ERR_FTOKKEY, 1, sem_inf[i].ftok_key, ERR_SEMID, 1, sem_inf[i].sem_id);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15)
+					ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno, 0,
+					ERR_FTOKKEY, 1, sem_inf[i].ftok_key, ERR_SEMID, 1, sem_inf[i].sem_id);
 		}
 	}
-
 	/* First try to access shared memory based on the database FTOK id. Only need to do the ftok returned by the first
 	   FTOK done above as it was the only method where the shared memory and semaphore had the same key.
 
@@ -147,7 +150,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 		{
 			save_errno = errno;
 			mu_all_version_release_standalone(sem_inf);
-			rts_error(VARLSTCNT(5) ERR_DBOPNERR, 2, RTS_ERROR_TEXT(db_fn), save_errno);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBOPNERR, 2, RTS_ERROR_TEXT(db_fn), save_errno);
 		}
 #		ifdef __MVS__
 		if (-1 == gtm_zos_tag_to_policy(fd, TAG_BINARY, &realfiletag))
@@ -157,7 +160,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 		if (0 != rc)
 		{
 			mu_all_version_release_standalone(sem_inf);
-			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("LSEEKREAD()"), CALLFROM, rc);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("LSEEKREAD()"), CALLFROM, rc);
 		}
 		CLOSEFILE_RESET(fd, rc);	/* resets "fd" to FD_INVALID */
 		if (0 != v15_csd.shmid && INVALID_SHMID != v15_csd.shmid)
@@ -166,7 +169,7 @@ void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
 	if (-1 != shmid)
 	{
 		mu_all_version_release_standalone(sem_inf);
-		rts_error(VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
 				save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
 	}
 }
@@ -179,17 +182,21 @@ void mu_all_version_release_standalone(sem_info *sem_inf)
 	int		i, rc, save_errno;
 
 	/* Note that we ignore most errors in this routine as we may get called with the alleged semaphores in
-	   just about any state.
-	*/
+	 * just about any state.
+	 */
 	for (i = 0; FTOK_ID_CNT > i; ++i)
 	{	/* release/delete any held semaphores in this set */
 		if (sem_inf[i].sem_id && -1 != sem_inf[i].sem_id)
 		{
 			rc = semctl(sem_inf[i].sem_id, 0, IPC_RMID);
-			if (-1 == rc && EIDRM != errno)
-			{	/* Don't care if semaphore already removed */
+			if (-1 == rc)
+			{
 				save_errno = errno;
-				send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(remid)"), CALLFROM, save_errno);
+				if (!SEM_REMOVED(save_errno))
+				{	/* Don't care if semaphore already removed (probably by a concurrent mupip rundown) */
+					send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8)
+						ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(remid)"), CALLFROM, save_errno);
+				}
 			}
 			sem_inf[i].sem_id = 0;	/* Clear so we don't repeat if redriven */
 		}
diff --git a/sr_unix/mu_rndwn_file.c b/sr_unix/mu_rndwn_file.c
index 3a225cf..420d8ba 100644
--- a/sr_unix/mu_rndwn_file.c
+++ b/sr_unix/mu_rndwn_file.c
@@ -993,7 +993,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
 			if (0 != shm_rmid(udi->shmid))
 			{
 				save_errno = errno;
-				if ((EINVAL != save_errno) && (EIDRM != save_errno))
+				if (!SHM_REMOVED(save_errno))
 				{
 					assert(FALSE);
 					RNDWN_ERR("!AD -> Error removing shared memory.", reg);
diff --git a/sr_unix/mu_rndwn_rlnkctl.c b/sr_unix/mu_rndwn_rlnkctl.c
new file mode 100644
index 0000000..6aea790
--- /dev/null
+++ b/sr_unix/mu_rndwn_rlnkctl.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include <rtnhdr.h>		/* needed for zroutines.h */
+#include "zroutines.h"
+#include "cli.h"
+#include "cliif.h"
+#include "cli_parse.h"
+#endif
+#include "mu_rndwn_rlnkctl.h"	/* for mupip_rctldump prototype */
+
+#ifdef AUTORELINK_SUPPORTED
+error_def(ERR_MUPCLIERR);
+#endif
+
+void mu_rndwn_rlnkctl(void)
+{
+#	ifdef AUTORELINK_SUPPORTED
+	open_relinkctl_sgm	*linkctl;
+	relinkshm_hdr_t		*shm_hdr;
+	relinkrec_t		*linkrec;
+	relinkctl_data		*hdr;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	char			objdir[GTM_PATH_MAX];
+	int			i, j, recnum, n_records, shmid, shm_stat, save_errno;
+	unsigned short		max_len;
+	mstr			dir;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	TREF(is_mu_rndwn_rlnkctl) = TRUE;	/* relinkctl_open and relinkctl_rundown check this flag to act differently */
+	if (TREF(parms_cnt))
+	{
+		assert(1 == TREF(parms_cnt));
+		max_len = SIZEOF(objdir);
+		if (!cli_get_str("WHAT", objdir, &max_len))
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+		dir.addr = objdir;
+		dir.len = max_len;
+		linkctl = relinkctl_attach(&dir);
+		assert(linkctl == TREF(open_relinkctl_list));
+		assert((NULL == linkctl) || (NULL == linkctl->next));
+	} else
+		zro_init();
+	relinkctl_rundown(TRUE, FALSE);	/* will rundown one or more linkctl files opened above */
+	TREF(is_mu_rndwn_rlnkctl) = FALSE;
+#	endif	/* AUTORELINK_SUPPORTED */
+}
+
diff --git a/sr_unix/do_shmat.h b/sr_unix/mu_rndwn_rlnkctl.h
similarity index 67%
copy from sr_unix/do_shmat.h
copy to sr_unix/mu_rndwn_rlnkctl.h
index c4143a7..81aaf1d 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/mu_rndwn_rlnkctl.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -9,9 +9,9 @@
  *								*
  ****************************************************************/
 
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef MU_RNDWN_RLNKCTL_INCLUDED
+#define MU_RNDWN_RLNKCTL_INCLUDED
 
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void mu_rndwn_rlnkctl(void);
 
-#endif
+#endif /* MU_RNDWN_RLNKCTL_INCLUDED */
diff --git a/sr_unix/mupip_cmd.c b/sr_unix/mupip_cmd.c
index a4b03b0..9ee21d9 100644
--- a/sr_unix/mupip_cmd.c
+++ b/sr_unix/mupip_cmd.c
@@ -53,6 +53,7 @@
 #include "mupip_ftok.h"
 #include "mupip_endiancvt.h"
 #include "mupip_crypt.h"
+#include "mupip_hash.h"
 #include "gtmsource.h"
 #include "gtmrecv.h"
 #include "read_db_files_from_gld.h"	/* Needed for updproc.h */
@@ -61,6 +62,8 @@
 #ifdef GTM_SNAPSHOT
 #include "db_snapshot.h"
 #endif
+#include "mupip_rctldump.h"
+#include "mu_rndwn_rlnkctl.h"
 
 static CLI_ENTRY mup_set_journal_qual[] = {
 	{ "ALIGNSIZE",       0, 0, 0, 0, 0, 0, VAL_REQ,        1, NON_NEG, VAL_NUM, 0 },
@@ -497,6 +500,7 @@ static CLI_ENTRY	gtmsource_qual[] = {
 	{"FILTER",               0, 0,                0,                      0, 0,                                  0, VAL_REQ,        0, NON_NEG, VAL_STR, 0 },
 	{"FREEZE",               0, inst_freeze_qual, 0,                      0, 0,                                  0, VAL_NOT_REQ,    0, NON_NEG, VAL_STR, 0 },
 	{"INSTSECONDARY",        0, 0,                0,                      0, 0,                                  0, VAL_REQ,        0, NON_NEG, VAL_STR, 0 },
+	{"JNLFILEONLY",          0, 0,                0,                      0, 0,                                  0, VAL_DISALLOWED, 1, NEG,     VAL_N_A, 0 },
 	{"JNLPOOL",              0, inst_edit_qual,   0,                      0, cli_disallow_mupip_replic_editinst, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
 	{"LOG",                  0, 0,                0,                      0, 0,                                  0, VAL_REQ,        0, NON_NEG, VAL_STR, 0 },
 	{"LOG_INTERVAL",         0, 0,                0,                      0, 0,                                  0, VAL_REQ,        0, NON_NEG, VAL_NUM, 0 },
@@ -613,10 +617,15 @@ static	CLI_PARM	mup_rundown_parm[] = {
 	{ "", "", PARM_REQ}
 };
 
+/* Note: "R" is a duplicate of "REGION". It is there so -R usages continue to be treated as -REGION and not have an
+ * ambiguity with "RELINKCTL".
+ */
 static	CLI_ENTRY	mup_rundown_qual[] = {
-	{ "FILE",   	mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
-	{ "OVERRIDE",	mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
-	{ "REGION", 	mupip_rundown, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+	{ "FILE",	mupip_rundown,    0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+	{ "OVERRIDE",	mupip_rundown,    0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 },
+	{ "R",		mupip_rundown,    0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+	{ "REGION",	mupip_rundown,    0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
+	{ "RELINKCTL",	mu_rndwn_rlnkctl, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0,       0,       0 },
 	{ 0 }
 };
 
@@ -677,9 +686,10 @@ static readonly CLI_PARM mup_trig_sel_parm[] = {
 };
 
 static 	CLI_ENTRY	mup_trigger_qual[] = {
-{ "NOPROMPT",		  mupip_trigger, 0, 0,                 0, 0,		        0, VAL_NOT_REQ,	0, NON_NEG, VAL_STR,  0 },
-{ "SELECT",               mupip_trigger, 0, mup_trig_sel_parm, 0, 0,			0, VAL_NOT_REQ,	1, NON_NEG, VAL_STR,  0 },
-{ "TRIGGERFILE",	  mupip_trigger, 0, 0,                 0, 0,		        0, VAL_REQ,	0, NON_NEG, VAL_STR,  0 },
+{ "NOPROMPT",    mupip_trigger, 0, 0,                 0, 0, 0, VAL_NOT_REQ,     0, NON_NEG, VAL_STR,  0 },
+{ "SELECT",      mupip_trigger, 0, mup_trig_sel_parm, 0, 0, 0, VAL_NOT_REQ,     1, NON_NEG, VAL_STR,  0 },
+{ "TRIGGERFILE", mupip_trigger, 0, 0,                 0, 0, 0, VAL_REQ,         0, NON_NEG, VAL_STR,  0 },
+{ "UPGRADE",     mupip_trigger, 0, 0,                 0, 0, 0, VAL_DISALLOWED,  0, NON_NEG, VAL_N_A,  0 },
 { 0 }
 };
 #endif
@@ -704,6 +714,11 @@ static	CLI_ENTRY	mup_downgrade_qual[] = {
 { 0 }
 };
 
+static	CLI_PARM	mup_rctldump_parm[] = {
+	{ "DIRECTORY", "Directory: ", PARM_REQ},
+	{ "",          "",            PARM_REQ}
+};
+
 GBLDEF	CLI_ENTRY	mupip_cmd_ary[] = {
 { "BACKUP",	mupip_backup,	mup_backup_qual,	mup_backup_parm,	0, cli_disallow_mupip_backup,	0, VAL_DISALLOWED, 2, 0, 0, 0 },
 { "CONVERT",	mupip_cvtpgm,	mup_convert_qual,	mup_convert_parm,	0, 0,				0, VAL_DISALLOWED, 2, 0, 0, 0 },
@@ -716,12 +731,14 @@ GBLDEF	CLI_ENTRY	mupip_cmd_ary[] = {
 { "EXTRACT",	mu_extract,	mup_extract_qual,	mup_extract_parm,	0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "FREEZE",	mupip_freeze,	mup_freeze_qual,	mup_freeze_parm,	0, cli_disallow_mupip_freeze,	0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "FTOK",	mupip_ftok,	mup_ftok_qual,		mup_ftok_parm,		0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
+{ "HASH",	mupip_hash,	0,			0,			0, 0,				0, VAL_DISALLOWED, MAX_PARMS, 0, 0, 0 },
 { "HELP",	util_help,	0,			0,			0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "INTEG",	mupip_integ,	mup_integ_qual,		mup_integ_parm,		0, cli_disallow_mupip_integ,	0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "INTRPT",	mupip_intrpt,	0,			mup_intrpt_parm,	0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "JOURNAL",	mupip_recover,	mup_journal_qual,	mup_journal_parm,	0, cli_disallow_mupip_journal,	0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "LOAD",	mupip_cvtgbl,	mup_load_qual,		mup_load_parm,		0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "QUIT",	mupip_quit,	0,			0,			0, 0,				0, VAL_DISALLOWED, 0, 0, 0, 0 },
+{ "RCTLDUMP",	mupip_rctldump, 0,                      mup_rctldump_parm,	0, 0,				0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "REORG",	mupip_reorg,	mup_reorg_qual,		mup_reorg_parm,		0, cli_disallow_mupip_reorg,	0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "REPLICATE",	0,		mup_replicate_qual,	mup_replicate_parm,	0, cli_disallow_mupip_replicate,0, VAL_DISALLOWED, 1, 0, 0, 0 },
 { "RESTORE",	mupip_restore,	mup_restore_qual,	mup_restore_parm,	0, 0,				0, VAL_DISALLOWED, 2, 0, 0, 0 },
diff --git a/sr_unix/mupip_cmd_disallow.c b/sr_unix/mupip_cmd_disallow.c
index fe32ba0..94d3ffc 100644
--- a/sr_unix/mupip_cmd_disallow.c
+++ b/sr_unix/mupip_cmd_disallow.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2002, 2013 Fidelity Information Services, Inc.*
+ *	Copyright 2002, 2014 Fidelity Information Services, Inc.*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -512,8 +512,8 @@ boolean_t cli_disallow_mupip_trigger(void)
 
 	*cli_err_str_ptr = 0;
 
-	/* any MUPIP TRIGGER command has to have either SELECT or TRIGGERFILE */
-	disallow_return_value = !(d_c_cli_present("SELECT") || d_c_cli_present("TRIGGERFILE"));
+	/* any MUPIP TRIGGER command has to have either SELECT or TRIGGERFILE or UPGRADE */
+	disallow_return_value = !(d_c_cli_present("SELECT") || d_c_cli_present("TRIGGERFILE") || d_c_cli_present("UPGRADE"));
 	CLI_DIS_CHECK_N_RESET;
 	return FALSE;
 }
diff --git a/sr_unix/mupip_cvtgbl.c b/sr_unix/mupip_cvtgbl.c
index d3a8a3b..9fe7736 100644
--- a/sr_unix/mupip_cvtgbl.c
+++ b/sr_unix/mupip_cvtgbl.c
@@ -31,6 +31,8 @@
 #include "mu_outofband_setup.h"
 #include <gtm_fcntl.h>
 #include <errno.h>
+#include "muextr.h"
+#include <regex.h>
 
 GBLREF	int		gv_fillfactor;
 GBLREF	bool		mupip_error_occurred;
@@ -46,9 +48,13 @@ error_def(ERR_LOADBGSZ);
 error_def(ERR_LOADBGSZ2);
 error_def(ERR_LOADEDSZ);
 error_def(ERR_LOADEDSZ2);
+error_def(ERR_LDBINFMT);
 
-#define	MAX_ONERROR_VALUE_LEN	11	/* PROCEED, STOP, INTERACTIVE are the choices with INTERACTIVE being the maximum */
-#define	MAX_FORMAT_VALUE_LEN	 6	/* ZWR, BINARY, GO, GOQ are the choices with BINARY being the longest */
+#define CHAR_TO_READ_LINE1_BIN	STR_LIT_LEN("d0GDS BINARY")  /* read first 12 characters to check file is binary [d\0GDS BINARY] */
+#define CHAR_TO_READ_LINE1	1030 + 1 - CHAR_TO_READ_LINE1_BIN /* line 1 after 12 chars if not BINARY max[Label^%GO]=1030+\n */
+#define CHAR_TO_READ_LINE2	STR_LIT_LEN("GT.M 11-11-2090  12:12:12 ZWR") + 1 /* GT.M 11-11-2090  12:12:12 ZWR + newline*/
+#define	MAX_ONERROR_VALUE_LEN	STR_LIT_LEN("INTERACTIVE") /* PROCEED, STOP, INTERACTIVE are the choices with INTERACTIVE as max */
+#define	MAX_FORMAT_VALUE_LEN	STR_LIT_LEN("BINARY") /* ZWR, BINARY, GO, GOQ are the choices with BINARY being the longest */
 
 void mupip_cvtgbl(void)
 {
@@ -56,11 +62,13 @@ void mupip_cvtgbl(void)
 	char		fn[MAX_FN_LEN + 1];
 	unsigned char	buff[MAX_ONERROR_VALUE_LEN];
 	uint4		begin, end;
-	int		i, format;
+	int		i, file_format;
 	uint4	        cli_status;
 	gtm_int64_t	begin_i8, end_i8;
-	DCL_THREADGBL_ACCESS;
+	char		*line1_ptr, *line2_ptr;
+	int		line1_len, line2_len;
 
+	DCL_THREADGBL_ACCESS;
 	SETUP_THREADGBL_ACCESS;
 	assert(MAX_ONERROR_VALUE_LEN > MAX_FORMAT_VALUE_LEN);	/* so the buff[] definition above is good for FORMAT and ONERROR */
 	/* If an online rollback occurs when we are loading up the database with new globals and takes us back to a prior logical
@@ -85,7 +93,7 @@ void mupip_cvtgbl(void)
 			mupip_exit(ERR_MUPCLIERR);
 	} else if (!cli_get_str("FILE", fn, &fn_len))  /* User wants to read from a file. */
 		mupip_exit(ERR_MUPCLIERR); /* Neither -STDIN nor file name specified. */
-	file_input_init(fn, fn_len);
+	file_input_init(fn, fn_len, IOP_EOL);
 	if (mupip_error_occurred)
 		exit(-1);
 	mu_outofband_setup();
@@ -127,7 +135,6 @@ void mupip_cvtgbl(void)
 			gv_fillfactor = MAX_FILLFACTOR;
 	} else
 		gv_fillfactor = MAX_FILLFACTOR;
-
 	if (cli_present("ONERROR") == CLI_PRESENT)
 	{
 		len = SIZEOF(buff);
@@ -156,30 +163,119 @@ void mupip_cvtgbl(void)
 		}
 	} else
 		onerror = ONERROR_PROCEED; /* Default: Proceed on error */
-
+	file_format = get_file_format(&line1_ptr, &line2_ptr, &line1_len, &line2_len); /* Get file's format reading it's header */
 	if (cli_present("FORMAT") == CLI_PRESENT)
 	{
 		len = SIZEOF(buff);
 		if (!cli_get_str("FORMAT", (char *)buff, &len))
-			go_load(begin, end);
+			go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
 		else
 		{
 		        lower_to_upper(buff, buff, len);
 			if (!memcmp(buff, "ZWR", len))
-				go_load(begin, end);
+			{
+				if (MU_FMT_ZWR == file_format)
+					go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+				else
+					mupip_exit(ERR_LDBINFMT);
+			}
 			else if (!memcmp(buff, "BINARY", len))
-				bin_load(begin, end);
+			{
+				if (MU_FMT_BINARY == file_format)
+					bin_load(begin, end, line1_ptr, line1_len);
+				else
+					mupip_exit(ERR_LDBINFMT);
+			}
 			else if (!memcmp(buff, "GO", len))
-				go_load(begin, end);
+			{
+				if (MU_FMT_GO == file_format)
+					go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+				else
+					mupip_exit(ERR_LDBINFMT);
+			}
 			else if (!memcmp(buff, "GOQ", len))
-				goq_load();
-			else
 			{
-			        util_out_print("Illegal format for load",TRUE);
-				mupip_exit(ERR_MUPCLIERR);
+				if (MU_FMT_GOQ == file_format)
+					goq_load();
+				else
+					mupip_exit(ERR_LDBINFMT);
+			} else
+			{
+					util_out_print("Illegal file format for load",TRUE);
+					mupip_exit(ERR_MUPCLIERR);
 			}
 		}
 	} else
-		go_load(begin, end);
+	{
+		if (MU_FMT_BINARY == file_format)
+			bin_load(begin, end, line1_ptr, line1_len);
+		else if (MU_FMT_ZWR == file_format || MU_FMT_GO == file_format)
+			go_load(begin, end, line1_ptr, line1_len, line2_ptr, line2_len);
+		else if (MU_FMT_UNRECOG == file_format)
+			mupip_exit(ERR_LDBINFMT);
+	}
 	mupip_exit(mupip_error_occurred ? ERR_MUNOFINISH : SS_NORMAL);
 }
+
+int get_file_format(char **line1_ptr, char **line2_ptr, int *line1_len, int *line2_len)
+{
+	char	*c, *ctop;
+	char	*line1, *line2;
+	int	tmp_len;
+	regex_t	regexGO, regexZWR;
+	int	count, newlinepos;
+
+	line1 = (char *)malloc(CHAR_TO_READ_LINE1_BIN + CHAR_TO_READ_LINE1 + CHAR_TO_READ_LINE2); /* Allocate max space needed */
+	*line1_len = file_input_read_xchar(line1, CHAR_TO_READ_LINE1_BIN);
+	if (0 < *line1_len)
+	{
+		*line1_ptr = line1;
+		if (0 == memcmp(line1 + 6, "BINARY", STR_LIT_LEN("BINARY"))) /* If file is binary do not look further */
+			return MU_FMT_BINARY;
+		for (newlinepos = -1, count = 0, c = line1, ctop = c + *line1_len; c < ctop; c++, count++)
+		{
+			if ('\n' == *c)
+			{
+				newlinepos = count + 1;
+				break;
+			}
+		}
+		if (0 < newlinepos) /* If the line 1 length is less than 12 chars, line1 has characters from line 2 as well */
+		{
+			*line2_len = *line1_len - newlinepos;
+			*line1_len = newlinepos - 1;
+			line2 = line1 + newlinepos;
+			tmp_len = file_input_get_xchar(line2 + *line2_len,  CHAR_TO_READ_LINE2);
+			*line2_len += tmp_len;
+		} else
+		{
+			tmp_len = file_input_get_xchar(line1 + *line1_len,  CHAR_TO_READ_LINE1);
+			*line1_len += tmp_len;
+			line2 = line1 + *line1_len + 1;
+			*line2_len = file_input_get_xchar(line2, CHAR_TO_READ_LINE2);
+		}
+		*line2_ptr = line2;
+		if (0 < *line2_len)
+		{
+			/* Compile regular expression "GT.M DD-MON-YEAR  24:60:SS ZWR"*/
+			regcomp(&regexZWR, "(GT.M )?[0-9]{2}[-]([A-Z]{3})[-][0-9]{4}[ ]{1,2}[0-9]{2}[:][0-9]{2}[:][0-9]{2} ZWR"
+					, REG_EXTENDED);
+			if (!regexec(&regexZWR, line2, 0, NULL, 0) || (0 == memcmp(line2, "; ZWR", STR_LIT_LEN("; ZWR"))))
+			{
+				regfree(&regexZWR);
+				return MU_FMT_ZWR;
+			}
+			regfree(&regexZWR);
+			/* Compile regular expression "GT.M DD-MON-YEAR  24:60:SS"*/
+			regcomp(&regexGO, "(GT.M )?[0-9]{2}[-]([A-Z]{3})[-][0-9]{4}[ ]{1,2}[0-9]{2}[:][0-9]{2}[:][0-9]{2}"
+					, REG_EXTENDED);
+			if (!regexec(&regexGO, line2, 0, NULL, 0) || (0 == memcmp(line2, "; GLO", STR_LIT_LEN("; GLO"))))
+			{
+				regfree(&regexGO);
+				return MU_FMT_GO;
+			}
+			regfree(&regexGO);
+		}
+	}
+	return MU_FMT_UNRECOG;
+}
diff --git a/sr_unix/mupip_exit_handler.c b/sr_unix/mupip_exit_handler.c
index dd79f22..8d9631d 100644
--- a/sr_unix/mupip_exit_handler.c
+++ b/sr_unix/mupip_exit_handler.c
@@ -124,7 +124,7 @@ void mupip_exit_handler(void)
 		recvpool.recvpool_ctl = NULL;
 	}
 	gv_rundown(); /* also takes care of detaching from the journal pool */
-	relinkctl_rundown(TRUE);
+	relinkctl_rundown(TRUE, TRUE);	/* decrement relinkctl-attach & rtnobj-reference counts */
 	/* Log the exit of replication servers. In case they are exiting abnormally, their log file pointers
 	 * might not be set up. In that case, use "stderr" for logging.
 	 */
diff --git a/sr_unix/mupip_hash.c b/sr_unix/mupip_hash.c
new file mode 100644
index 0000000..7edeeff
--- /dev/null
+++ b/sr_unix/mupip_hash.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made available	*
+ *	under a license.  If you do not know the terms of	*
+ *	the license, please stop and do not read further.	*
+ *								*
+ ****************************************************************/
+
+#include "mdef.h"
+#include "util.h"
+/* #include "cli.h" */
+#include "gtmio.h"
+#include "gtm_threadgbl.h"
+#include "mmrhash.h"
+#include "mupip_hash.h"
+
+/* Display the 128-bit MurmurHash3 value(s) for the file(s) given on the command line.
+ * For example,
+ *	% mupip hash foo.m bar.m
+ *	foo.m: 77c5e66fcaedebf32199d87b0f6b6d80
+ *	bar.m: 4b2a2ddc6803a30f4a769d4f6d9c8bd5
+ */
+
+void mupip_hash(void)
+{
+	int			i, fd, status, size;
+	hash128_state_t		hash_state;
+	gtm_uint16		hash;
+	unsigned char		hash_hex[32], readbuf[4096];
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	for (i = 0; i < TREF(parms_cnt); i++)
+	{
+		OPENFILE(TAREF1(parm_ary, i), O_RDONLY, fd);
+		if (fd < 0)
+		{
+			util_out_print("Error opening !AZ for read", TRUE, TAREF1(parm_ary, i));
+			continue;
+		}
+		size = 0;
+		HASH128_STATE_INIT(hash_state, 0);
+		while (1)
+		{
+			DOREADRL(fd, readbuf, SIZEOF(readbuf), status);
+			if (-1 == status)
+			{
+				util_out_print("Error reading from !AZ", TRUE, TAREF1(parm_ary, i));
+				goto skipfile;
+			}
+			if (0 == status)
+				break;
+			gtmmrhash_128_ingest(&hash_state, readbuf, status);
+			size += status;
+		}
+		gtmmrhash_128_result(&hash_state, size, &hash);
+		gtmmrhash_128_hex(&hash, hash_hex);
+		util_out_print("!AZ: !AD", TRUE, TAREF1(parm_ary, i), SIZEOF(hash_hex), hash_hex);
+	skipfile:
+		CLOSEFILE_RESET(fd, status);
+	}
+}
diff --git a/sr_avms/release_name.h b/sr_unix/mupip_hash.h
similarity index 71%
copy from sr_avms/release_name.h
copy to sr_unix/mupip_hash.h
index 632b116..0cc2069 100644
--- a/sr_avms/release_name.h
+++ b/sr_unix/mupip_hash.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -9,6 +9,4 @@
  *								*
  ****************************************************************/
 
-#define GTM_RELEASE_NAME	"GT.M V6.2-000 VMS AXP"
-#define GTM_PRODUCT		"GT.M"
-#define GTM_VERSION		"V6.2"
+void mupip_hash(void);
diff --git a/sr_unix/mupip_rctldump.c b/sr_unix/mupip_rctldump.c
new file mode 100644
index 0000000..236b753
--- /dev/null
+++ b/sr_unix/mupip_rctldump.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include <rtnhdr.h>		/* needed for zroutines.h */
+#include "zroutines.h"
+#include "cli.h"
+#include "cliif.h"
+#include "cli_parse.h"
+#include "zshow.h"
+#endif
+#include "mupip_rctldump.h"	/* for mupip_rctldump prototype */
+
+#ifdef AUTORELINK_SUPPORTED
+error_def(ERR_MUPCLIERR);
+#endif
+
+void mupip_rctldump(void)
+{
+#	ifdef AUTORELINK_SUPPORTED
+	unsigned short		max_len;
+	mstr			dir;
+	char			objdir[GTM_PATH_MAX];
+	open_relinkctl_sgm	*linkctl;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	if (TREF(parms_cnt))
+	{
+		assert(1 == TREF(parms_cnt));
+		max_len = SIZEOF(objdir);
+		if (!cli_get_str("DIRECTORY", objdir, &max_len))
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+		dir.addr = objdir;
+		dir.len = max_len;
+		linkctl = relinkctl_attach(&dir);
+		assert(linkctl == TREF(open_relinkctl_list));
+		assert((NULL == linkctl) || (NULL == linkctl->next));
+	} else
+		zro_init();
+	util_out_print("", RESET);	/* Reset output buffer */
+	zshow_rctldump(NULL);		/* callee knows caller is mupip_rctldump type based on the NULL parameter */
+#	endif	/* AUTORELINK_SUPPORTED */
+}
+
diff --git a/sr_unix/do_shmat.h b/sr_unix/mupip_rctldump.h
similarity index 68%
copy from sr_unix/do_shmat.h
copy to sr_unix/mupip_rctldump.h
index c4143a7..d2de5f0 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/mupip_rctldump.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -9,9 +9,9 @@
  *								*
  ****************************************************************/
 
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef MUPIP_RCTLDUMP_INCLUDED
+#define MUPIP_RCTLDUMP_INCLUDED
 
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void mupip_rctldump(void);
 
-#endif
+#endif /* MUPIP_RCTLDUMP_INCLUDED */
diff --git a/sr_unix/mupip_rundown.c b/sr_unix/mupip_rundown.c
index d6e7769..178984b 100644
--- a/sr_unix/mupip_rundown.c
+++ b/sr_unix/mupip_rundown.c
@@ -99,7 +99,7 @@ void mupip_rundown(void)
 	SETUP_THREADGBL_ACCESS;
 	exit_status = SS_NORMAL;
 	file = (CLI_PRESENT == cli_present("FILE"));
-	region = (CLI_PRESENT == cli_present("REGION"));
+	region = (CLI_PRESENT == cli_present("REGION")) || (CLI_PRESENT == cli_present("R"));
 	TREF(skip_file_corrupt_check) = TRUE;	/* rundown the database even if csd->file_corrupt is TRUE */
 	arg_present = (0 != TREF(parms_cnt));
 	if ((file == region) && (TRUE == file))
diff --git a/sr_unix/mupip_trigger.c b/sr_unix/mupip_trigger.c
index 3579268..0503005 100644
--- a/sr_unix/mupip_trigger.c
+++ b/sr_unix/mupip_trigger.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -11,6 +11,8 @@
 
 #include "mdef.h"
 
+#ifdef GTM_TRIGGER
+
 #include <errno.h>
 #include "gtm_stdlib.h"		/* for exit() */
 #include "gtm_limits.h"
@@ -20,6 +22,7 @@
 #include "gdsroot.h"
 #include "gdsbt.h"
 #include "gdsfhead.h"
+#include "filestruct.h"
 #include <rtnhdr.h>
 #include "gv_trigger.h"
 #include "mupip_trigger.h"
@@ -27,11 +30,21 @@
 #include "trigger_select_protos.h"
 #include "util.h"
 #include "mupip_exit.h"
+#include "change_reg.h"
+#include "targ_alloc.h"
+#include "gvcst_protos.h"
+#include "trigger_upgrade_protos.h"
+
+GBLREF	gd_addr		*gd_header;
+#ifdef DEBUG
+GBLREF	boolean_t	is_replicator;
+#endif
 
+error_def(ERR_INVSTRLEN);
+error_def(ERR_MUNOACTION);
 error_def(ERR_MUPCLIERR);
 error_def(ERR_NOSELECT);
-error_def(ERR_MUNOACTION);
-error_def(ERR_INVSTRLEN);
+error_def(ERR_TRIGMODREGNOTRW);
 
 void mupip_trigger(void)
 {
@@ -41,8 +54,14 @@ void mupip_trigger(void)
 	unsigned short	sf_name_len;
 	int		local_errno;
 	struct stat	statbuf;
-	boolean_t	noprompt;
+	boolean_t	noprompt, trigger_error;
+	gd_region	*reg, *reg_top;
+	sgmnt_addrs	*csa;
+#	ifdef DEBUG
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
+#	endif
 	if (CLI_PRESENT == cli_present("TRIGGERFILE"))
 	{
 		noprompt = (CLI_PRESENT == cli_present("NOPROMPT"));
@@ -82,6 +101,42 @@ void mupip_trigger(void)
 			util_out_print("Error opening output file: !AD -- File exists", TRUE, sf_name_len, select_file_name);
 			mupip_exit(ERR_MUNOACTION);
 		}
-		(void)trigger_select(select_list, (uint4)select_list_len, select_file_name, (uint4)sf_name_len);
+		trigger_error = trigger_select_tpwrap(select_list, (uint4)select_list_len, select_file_name, (uint4)sf_name_len);
+		if (trigger_error)
+			mupip_exit(ERR_MUNOACTION);
+	}
+	if (CLI_PRESENT == cli_present("UPGRADE"))
+	{	/* Invoke MUPIP TRIGGER -UPGRADE */
+		gvinit();
+		DEBUG_ONLY(TREF(in_trigger_upgrade) = TRUE;)
+		for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+		{
+			GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+			csa = cs_addrs;
+			if (NULL == csa)	/* not BG or MM access method */
+				continue;
+			if (!csa->hdr->hasht_upgrade_needed)
+			{
+				util_out_print("Triggers in region !AD have already been upgraded", TRUE, REG_LEN_STR(reg));
+				continue;	/* ^#t already upgraded */
+			}
+			if (reg->read_only)
+				rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+			if (0 == gv_target->root)
+			{
+				util_out_print("No triggers found in region !AD and so no upgrade needed", TRUE, REG_LEN_STR(reg));
+				csa->hdr->hasht_upgrade_needed = FALSE;	/* Reset now that we know there is no ^#t global in this db.
+									 * Note: It is safe to do so even if we dont hold crit.
+									 */
+				continue;	/* no ^#t records exist in this region */
+			}
+			assert(!dollar_tlevel);
+			assert(!is_replicator);
+			trigger_upgrade(reg);
+			assert(!csa->hdr->hasht_upgrade_needed);	/* should have been cleared inside trigger_upgrade */
+			util_out_print("Triggers in region !AD have been upgraded", TRUE, REG_LEN_STR(reg));
+		}
+		DEBUG_ONLY(TREF(in_trigger_upgrade) = FALSE;)
 	}
 }
+#endif
diff --git a/sr_unix/mutex.c b/sr_unix/mutex.c
index 0735558..9acb9a9 100644
--- a/sr_unix/mutex.c
+++ b/sr_unix/mutex.c
@@ -54,6 +54,8 @@
 #include "gt_timer.h"
 #include "gtmio.h"
 #include "gtm_c_stack_trace.h"
+#include "sleep.h"
+#include "anticipatory_freeze.h"
 #ifdef DEBUG
 #include "wbox_test_init.h"
 #include "repl_msg.h"			/* needed by gtmsource.h */
@@ -94,9 +96,11 @@
 		BG_TRACE_PRO_ANY(CSA, EVENT);					\
 }
 
-GBLREF pid_t			process_id;
-GBLREF uint4			image_count;
 GBLREF int			num_additional_processors;
+GBLREF jnl_gbls_t		jgbl;
+GBLREF jnlpool_addrs		jnlpool;
+GBLREF pid_t			process_id;
+GBLREF uint4			image_count, mutex_per_process_init_pid;
 #ifdef MUTEX_MSEM_WAKE
 GBLREF volatile uint4           heartbeat_counter;
 #  ifdef POSIX_MSEM
@@ -106,18 +110,14 @@ static msemaphore		*mutex_wake_msem_ptr = NULL;
 #  endif
 static mutex_que_entry_ptr_t	msem_slot;
 #else
-GBLREF int			mutex_sock_fd;
 GBLREF fd_set			mutex_wait_on_descs;
+GBLREF int			mutex_sock_fd;
 #endif
-GBLREF	uint4			mutex_per_process_init_pid;
 #ifdef DEBUG
-GBLREF	jnlpool_addrs		jnlpool;
-GBLREF	boolean_t		in_mu_rndwn_file;
+GBLREF boolean_t		in_mu_rndwn_file;
 #endif
-GBLREF	jnl_gbls_t		jgbl;
 
 DECLARE_MUTEX_TRACE_CNTRS
-
 DECLARE_MUTEX_TEST_SIGNAL_FLAG
 
 static	boolean_t	woke_self;
@@ -491,7 +491,7 @@ static	enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
 	mutex_que_entry_ptr_t	free_slot;
 	int			redo_cntr;
 	int			queue_retry_counter_remq,
-			        quant_retry_counter_remq,
+				quant_retry_counter_remq,
 				queue_retry_counter_insq,
 				quant_retry_counter_insq;
 #	ifdef MUTEX_MSEM_WAKE
@@ -590,6 +590,7 @@ static	enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
 				 * PROBE_BG_TRACE_PRO_ANY macro.
 				 */
 				PROBE_BG_TRACE_PRO_ANY(csa, mutex_queue_full);
+				csa->probecrit_rec.p_crit_que_full++;
 				MUTEX_DPRINT2("%d: Free Queue full\n", process_id);
 				/* When I can't find a free slot in the queue repeatedly, it means that there is no progress
 				 * in the system. A recovery attempt might be warranted in this scenario. The trick is to
@@ -598,7 +599,7 @@ static	enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
 				 * done, though queueing isn't.
 				 */
 			}
-			MICROSEC_SLEEP(ONE_MILLION - 1);	/* Wait a second, then try again */
+			SLEEP_USEC(ONE_MILLION - 1, FALSE);	/* Wait a second, then try again */
 			mutex_deadlock_check(addr, csa);
 			if (++redo_cntr < MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR)
 				break;
@@ -718,14 +719,16 @@ void	gtm_mutex_init(gd_region *reg, int n, bool crash)
 }
 
 static enum cdb_sc write_lock_spin(gd_region *reg,
-			           mutex_spin_parms_ptr_t mutex_spin_parms,
-				   int crash_count,
-				   int attempt_recovery,
-				   mutex_lock_t mutex_lock_type)
+					 mutex_spin_parms_ptr_t mutex_spin_parms,
+					 int crash_count,
+					 int attempt_recovery,
+					 mutex_lock_t mutex_lock_type,
+					 gtm_uint64_t *spins,
+					 gtm_uint64_t *yields)
 {
 	int			write_sleep_spin_count, write_hard_spin_count;
-	sgmnt_addrs		*csa;
 	mutex_struct_ptr_t	addr;
+	sgmnt_addrs		*csa;
 #	ifdef MUTEX_REAL_SLEEP
 	int			micro_sleep_time;
 #	endif
@@ -749,6 +752,10 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
 				MUTEX_TEST_SIGNAL_HERE("WRTLCK NOW CRIT\n", FALSE);
 				csa->now_crit = TRUE;
 				MUTEX_TEST_SIGNAL_HERE("WRTLCK SUCCESS\n", FALSE);
+				assert(write_hard_spin_count <= *spins);
+				*spins -= write_hard_spin_count;			/* reduce by the number of unused */
+				assert(write_sleep_spin_count <= *yields);
+				*yields -= write_sleep_spin_count;			/* reduce by the number of unused */
 				return (cdb_sc_normal);
 			} else if (attempt_recovery)
 			{
@@ -756,7 +763,10 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
 				attempt_recovery = FALSE;
 			}
 			if (!write_hard_spin_count)	/* save memory reference on fast path */
+			{
 				write_hard_spin_count = num_additional_processors ? mutex_spin_parms->mutex_hard_spin_count : 1;
+				*spins += write_hard_spin_count;			/* start with max */
+			}
 		} while (--write_hard_spin_count);
 		/* Sleep for a very short duration */
 #		ifdef MUTEX_TRACE
@@ -769,12 +779,15 @@ static enum cdb_sc write_lock_spin(gd_region *reg,
 		micro_sleep_time = (nrand48(next_rand) & mutex_spin_parms->mutex_spin_sleep_mask) + 1;
 		assert(micro_sleep_time < ONE_MILLION);
 		assert(FALSE == csa->now_crit);
-		MICROSEC_SLEEP(micro_sleep_time);
+		SLEEP_USEC(micro_sleep_time, FALSE);
 #		else
 		rel_quant();
 #		endif
 		if (!write_sleep_spin_count)	/* save memory reference on fast path */
+		{
 			write_sleep_spin_count = mutex_spin_parms->mutex_sleep_spin_count;
+			*yields += write_sleep_spin_count;				/* start with max */
+		}
 	} while (--write_sleep_spin_count);
 	MUTEX_DPRINT4("%d: Could not acquire WRITE %sLOCK, held by %d\n", process_id,
 		(MUTEX_LOCK_WRITE == mutex_lock_type) ? "" : "IMMEDIATE ", addr->semaphore.u.parts.latch_pid);
@@ -786,60 +799,101 @@ static enum cdb_sc mutex_lock(gd_region *reg,
 			      int crash_count,
 			      mutex_lock_t mutex_lock_type)
 {
-	boolean_t		try_recovery;
+	boolean_t		epoch_count, try_recovery;
 	enum cdb_sc		status;
-	int			lock_attempts;
+	int 			n_queslots;
 	latch_t			local_crit_cycle;
+	mutex_struct_ptr_t 	addr;
+	node_local		*cnl;
 	pid_t			in_crit_pid;
 	sgmnt_addrs		*csa;
 	time_t			curr_time;
 	uint4			curr_time_uint4, next_alert_uint4;
+	gtm_uint64_t		failed_lock_attempts, queue_sleeps, spins, yields;
+	ABS_TIME 		atstart, atend;
 
 	csa = &FILE_INFO(reg)->s_addrs;
+	cnl = csa->nl;
 	/* Check that "mutex_per_process_init" has happened before we try to grab crit and that it was done with our current
 	 * pid (i.e. ensure that even in the case where parent did the mutex init with its pid and did a fork, the child process
 	 * has done a reinitialization with its pid). The only exception is if we are in "mu_rndwn_file" in which case we
 	 * know for sure there is no other pid accessing the database shared memory.
 	 */
 	assert((MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type) || (MUTEX_LOCK_WRITE == mutex_lock_type));
-	assert(mutex_per_process_init_pid == process_id || (0 == mutex_per_process_init_pid) && in_mu_rndwn_file);
+	assert((mutex_per_process_init_pid == process_id) || (0 == mutex_per_process_init_pid) && in_mu_rndwn_file);
 	MUTEX_TRACE_CNTR((MUTEX_LOCK_WRITE == mutex_lock_type) ? mutex_trc_lockw : mutex_trc_lockwim);
 	optimistic_attempts = 0;
-	lock_attempts = 0;
+	queue_sleeps = spins = yields = csa->probecrit_rec.p_crit_que_full = 0;
 	local_crit_cycle = 0;	/* this keeps us from doing a MUTEXLCKALERT on the first cycle in case the time latch is stale */
 	try_recovery = jgbl.onlnrlbk; /* salvage lock the first time if we are online rollback thereby reducing unnecessary waits */
+	epoch_count = cnl->doing_epoch;
+	if (csa->crit_probe)
+	{	/* run the active queue to find how many slots are left */
+		addr = csa->critical;
+		csa->probecrit_rec.p_crit_que_slots = (gtm_uint64_t)addr->queslots;		/* free = total number of slots */
+		csa->probecrit_rec.p_crit_que_slots -= verify_queue_lock((que_head_ptr_t)&addr->prochead); /* less used slots */
+		sys_get_curr_time(&atstart);							/* start time for the probecrit */
+	}
 	do
 	{
-		in_crit_pid = csa->nl->in_crit;
-		lock_attempts++;
+		in_crit_pid = cnl->in_crit;
 		MUTEX_TRACE_CNTR(mutex_trc_w_atmpts);
-		status = write_lock_spin(reg, mutex_spin_parms, crash_count, try_recovery, mutex_lock_type);
+		status = write_lock_spin(reg, mutex_spin_parms, crash_count, try_recovery, mutex_lock_type, &spins, &yields);
 		if ((cdb_sc_normal == status) || (MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type) || (cdb_sc_critreset == status))
+		{
+			failed_lock_attempts = spins + yields + queue_sleeps;
+			INCR_GVSTATS_COUNTER(csa, cnl, n_crit_success, 1);
+			if (epoch_count)
+				INCR_GVSTATS_COUNTER(csa, cnl, n_crits_in_epch, failed_lock_attempts);
+			INCR_GVSTATS_COUNTER(csa, cnl, n_crit_failed, failed_lock_attempts);
+			INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_failed, failed_lock_attempts * failed_lock_attempts);
+			if (yields)
+			{
+				INCR_GVSTATS_COUNTER(csa, cnl, n_crit_yields, yields);
+				INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_yields, yields * yields);
+			}
+			if (queue_sleeps)
+			{
+				INCR_GVSTATS_COUNTER(csa, cnl, n_crit_que_slps, queue_sleeps);
+				INCR_GVSTATS_COUNTER(csa, cnl, sq_crit_que_slps, queue_sleeps * queue_sleeps);
+			}
+			if (csa->crit_probe)
+			{
+				sys_get_curr_time(&atend);		/* end time for the probcrit */
+				atend = sub_abs_time(&atend, &atstart);	/* the times currently use usec but might someday use */
+				csa->probecrit_rec.t_get_crit =  ((atend.at_sec * 1000000) + atend.at_usec) * 1000; /* nanosecs? */
+				csa->probecrit_rec.p_crit_failed = failed_lock_attempts;
+				csa->probecrit_rec.p_crit_yields = yields;
+				csa->probecrit_rec.p_crit_que_slps = queue_sleeps;
+			}
 			return (status);
+		}
 		try_recovery = FALSE;		/* only try recovery once per MUTEXLCKALERT */
 		assert(cdb_sc_nolock == status);
 		time(&curr_time);
 		assert(MAXUINT4 > curr_time);
 		curr_time_uint4 = (uint4)curr_time;
 		next_alert_uint4 = csa->critical->stuckexec.cas_time;
-		if (curr_time_uint4 > next_alert_uint4)
-		{	/* We've waited long enough */
+		if ((curr_time_uint4 > next_alert_uint4) && !IS_REPL_INST_FROZEN)
+		{	/* We've waited long enough and the Instance is not frozen */
 			if (COMPSWAP_LOCK(&csa->critical->stuckexec.time_latch, next_alert_uint4, 0,
 				(curr_time_uint4 + MUTEXLCKALERT_INTERVAL), 0))
 			{	/* and no one else beat us to it */
 				MUTEX_DPRINT3("%d: Acquired STUCKEXEC time lock, to trace %d\n", process_id, in_crit_pid);
 				if (process_id == in_crit_pid)
-				{	/* This is just a precaution - shouldn't ever happen */
+				{	/* This is just a precaution - shouldn't ever happen and has no code to maintain gvstats */
 					assert(FALSE);
 					csa->now_crit = TRUE;
 					return (cdb_sc_normal);
 				}
-				if (in_crit_pid && (in_crit_pid == csa->nl->in_crit) && is_proc_alive(in_crit_pid, 0))
+				if (in_crit_pid && (in_crit_pid == cnl->in_crit) && is_proc_alive(in_crit_pid, 0))
 				{	/* and we're waiting on some living process */
 					if (local_crit_cycle == csa->critical->crit_cycle)
 					{	/* and things aren't moving */
 						assert(local_crit_cycle);
-						if (0 == csa->nl->onln_rlbk_pid)
+						if (IS_REPL_INST_FROZEN)		/* recheck to minimize spurious reports */
+							continue;
+						if (0 == cnl->onln_rlbk_pid)
 						{	/* not rollback - send_msg after trace less likely to lose process */
 							GET_C_STACK_FROM_SCRIPT("MUTEXLCKALERT", process_id, in_crit_pid,
 								csa->critical->crit_cycle);
@@ -852,8 +906,8 @@ static enum cdb_sc mutex_lock(gd_region *reg,
 						 * journal pool for its entire duration, use a different message
 						 */
 						send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_ORLBKINPROG, 3,
-								csa->nl->onln_rlbk_pid, DB_LEN_STR(reg));
-						assert(csa->nl->in_crit == csa->nl->onln_rlbk_pid);
+								cnl->onln_rlbk_pid, DB_LEN_STR(reg));
+						assert(cnl->in_crit == cnl->onln_rlbk_pid);
 					}
 				} else
 				{	/* nobody home */
@@ -868,6 +922,7 @@ static enum cdb_sc mutex_lock(gd_region *reg,
 		}
 		if (0 == local_crit_cycle)
 			local_crit_cycle = csa->critical->crit_cycle;	/* sync first time waiter */
+		queue_sleeps++;
 		if (cdb_sc_dbccerr == mutex_sleep(csa, mutex_lock_type))
 			return (cdb_sc_dbccerr);
 	} while (TRUE);
diff --git a/sr_unix/mutexsp.h b/sr_unix/mutexsp.h
index 7e3dbe8..7d2e111 100644
--- a/sr_unix/mutexsp.h
+++ b/sr_unix/mutexsp.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -43,8 +43,6 @@
 
 #define ONE_MILLION 			1000000
 
-#define MICROSEC_SLEEP(x)		m_usleep(x)
-
 typedef struct
 {
 	uint4	pid;
diff --git a/sr_unix/obj_code.c b/sr_unix/obj_code.c
index 935386b..75b05fb 100644
--- a/sr_unix/obj_code.c
+++ b/sr_unix/obj_code.c
@@ -37,6 +37,9 @@
 #include "stringpool.h"
 #include "min_max.h"
 #include "rtn_src_chksum.h"
+#include "mmrhash.h"
+#include "arlinkdbg.h"
+#include "incr_link.h"
 
 GBLDEF uint4 			lits_text_size, lits_mval_size;
 
@@ -61,7 +64,9 @@ GBLREF int4			sym_table_size;
 GBLREF int4			linkage_size;
 GBLREF uint4			lnkrel_cnt;	/* number of entries in linkage Psect to relocate */
 GBLREF spdesc			stringpool;
+GBLREF short			object_name_len;
 GBLREF char			object_file_name[];
+GBLREF int			object_file_des;
 
 #define PTEXT_OFFSET SIZEOF(rhdtyp)
 
@@ -79,8 +84,10 @@ GBLREF char			object_file_name[];
  *	|     code	|  \                              \
  *	+ - - - - - - - +   |                              |
  *	| line num tbl	|   |- R/O releasable              |
- *	+ - - - - - - - +  /                               |- R/O releasable
- *	| lit text pool	| /                                |
+ *	+ - - - - - - - +   |                              |- R/O releasable
+ *	| lit text pool	|   |                              |
+ *	+---------------+  /                               |
+ *	| lkg name tbl 	| /              		   |
  *	+---------------+                                 /
  *	| lit mval tbl 	| \                              /
  *	+---------------+  |- R/W releasable
@@ -94,25 +101,30 @@ GBLREF char			object_file_name[];
  *	+---------------+
  *
  * Note in addition to the above layout, a "linkage section" is allocated at run time and is
- * also releasable.
+ * also releasable. The linkage table and the linkage name table are co-indexed and provide the
+ * routine or label names for the given entry. The linkage name table consists of unrelocated mstrs
+ * as they are only ever used once so need not be resolved.
  *
  * If GTM_DYNAMIC_LITERALS is enabled, the literal mval table becomes part of the R/O-release section.
  * In the case of shared libraries, this spares each process from having to take a malloced copy the lit mval table
  * at link time (sr_unix/incr_link.c). This memory saving optimization is only available on USHBIN-supported platforms
  */
 
+error_def(ERR_OBJFILERR);
+error_def(ERR_SYSCALL);
 error_def(ERR_TEXT);
 
-void cg_lab (mlabel *mlbl, char *do_emit);
+STATICFNDCL void cg_lab (mlabel *mlbl, char *do_emit);
 
 void obj_code (uint4 src_lines, void *checksum_ctx)
 {
-	int		i;
-	uint4		lits_pad_size, object_pad_size, lnr_pad_size;
+	int		i, status;
+	uint4		lits_pad_size, object_pad_size, lnr_pad_size, lnkname_pad_size;
 	int4		offset;
 	int4		old_code_size;
 	rhdtyp		rhead;
 	mline		*mlx, *mly;
+	gtm_uint16	objhash;
 	var_tabent	*vptr;
 	DCL_THREADGBL_ACCESS;
 
@@ -137,8 +149,8 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	curr_addr = PTEXT_OFFSET;
 	cg_phase = CGP_APPROX_ADDR;
 	cg_phase_last = CGP_NOSTATE;
-	IA64_ONLY(calculated_code_size = 0;)
-	IA64_DEBUG_ONLY(calculated_count = 0;)
+	IA64_ONLY(calculated_code_size = 0);
+	IA64_DEBUG_ONLY(calculated_count = 0);
 	code_gen();
 	code_size = curr_addr;
 	cg_phase = CGP_ADDR_OPT;
@@ -158,7 +170,7 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	if (!(cmd_qlf.qlf & CQ_OBJECT))
 		return;
 	/* Executable code offset setup */
-	IA64_ONLY(assert(!(PTEXT_OFFSET % SECTION_ALIGN_BOUNDARY));)
+	IA64_ONLY(assert(!(PTEXT_OFFSET % SECTION_ALIGN_BOUNDARY)));
 	rhead.ptext_adr = (unsigned char *)PTEXT_OFFSET;
 	rhead.ptext_end_adr = (unsigned char *)(size_t)code_size;
 	/* Line number table offset setup */
@@ -172,6 +184,11 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	rhead.literal_text_len = lits_text_size;
 	code_size += lits_text_size;
 	assert(0 == PADLEN(code_size, NATIVE_WSIZE));
+	/* Literal extern (linkage) names section (same # of entries as linkage table) */
+	rhead.linkage_names = (mstr *)(size_t)code_size;
+	code_size += ((linkage_size / SIZEOF(lnk_tabent)) * SIZEOF(mstr));
+	lnkname_pad_size = PADLEN(code_size, NATIVE_WSIZE);
+	code_size += lnkname_pad_size;
 	/* Literal mval section offset setup */
 	rhead.literal_adr = (mval *)(size_t)code_size;
 	rhead.literal_len = lits_mval_size / SIZEOF(mval);
@@ -207,6 +224,7 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	object_pad_size = PADLEN(code_size, OBJECT_SIZE_ALIGNMENT);
 	code_size += object_pad_size;
 	gtm_object_size = code_size;
+	rhead.object_len = gtm_object_size;
 	set_rtnhdr_checksum(&rhead, (gtm_rtn_src_chksum_ctx *)checksum_ctx);
 	rhead.objlabel = MAGIC_COOKIE;
 	rhead.temp_mvals = sa_temps[TVAL_REF];
@@ -214,11 +232,16 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	rhead.compiler_qlf = cmd_qlf.qlf;
 	if (cmd_qlf.qlf & CQ_EMBED_SOURCE)
 		rhead.routine_source_offset = TREF(routine_source_offset);
-	/* Start the creation of the output object */
+	/* Start the creation of the output object. On Linux, Solaris, and HPUX, we use ELF routines to push out native object
+	 * code wrapper so the wrapper is not part of the object code hash. However, on AIX, the native XCOFF wrapper is pushed
+	 * out by our own routines so is part of the hash. Note for AIX, the create_object_file() routine will duplicate the
+	 * hash initialization macro below after the native header is written out but before the GT.M object header is written.
+	 */
+	HASH128_STATE_INIT(TREF(objhash_state), 0);
 	create_object_file(&rhead);
 	cg_phase = CGP_MACHINE;
-	IA64_ONLY(generated_code_size = 0;)
-	IA64_DEBUG_ONLY(generated_count = 0;)
+	IA64_ONLY(generated_code_size = 0);
+	IA64_DEBUG_ONLY(generated_count = 0);
 	code_gen();
 	IA64_DEBUG_ONLY(
 	if (calculated_code_size != generated_code_size)
@@ -285,27 +308,35 @@ void obj_code (uint4 src_lines, void *checksum_ctx)
 	/* The label table */
 	if (mlabtab)
 		walktree((mvar *)mlabtab, cg_lab, (char *)TRUE);
-	/* Resolve locally defined symbols */
-	resolve_sym();
-	/* Output relocation entries for the linkage section */
-	output_relocation();
-	/* Output the symbol table text pool */
-	output_symbol();
+	resolve_sym();		/* Associate relocation entries for the same symbol/linkage-table slot together */
+	output_relocation();	/* Output relocation entries for the linkage section */
+	output_symbol();	/* Output the symbol table text pool */
 	/* If there is padding we need to do to fill out the object to the required boundary do it.. */
 	if (object_pad_size)
 	{
 		assert(STR_LIT_LEN(PADCHARS) >= object_pad_size);
 		emit_immed(PADCHARS, object_pad_size);
 	}
-	close_object_file();
+	finish_object_file();	/* Flushes object file buffers and writes remaining native object structures */
+	/* Get our 128 bit hash though only the first 8 bytes of it get saved in the routine header */
+	gtmmrhash_128_result(TADR(objhash_state), gtm_object_size, &objhash);
+	DBGARLNK((stderr, "obj_code: Computed hash value of 0x"lvaddr" for file %.*s\n", objhash.one, object_name_len,
+		  object_file_name));
+	if ((off_t)-1 == lseek(object_file_des, (off_t)(NATIVE_HDR_LEN + OFFSETOF(rhdtyp, objhash)), SEEK_SET))
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
+	emit_immed((char *)&objhash.one, SIZEOF(gtm_uint64_t));	/* Update 8 bytes of objhash in the file header */
+	buff_flush();						/* Push it out */
+	CLOSE_OBJECT_FILE(object_file_des, status);
+	if (-1 == status)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno);
 	/* Ready to make object visible. Rename from tmp name to real routine name */
-	rename_tmp_object_file(object_file_name);
+	RENAME_TMP_OBJECT_FILE(object_file_name);
 }
 
 /* Routine called to process a given label. Cheezy 2nd parm is due to general purpose
  * mechanism of the walktree routine that calls us.
  */
-void	cg_lab(mlabel *mlbl, char *do_emit)
+STATICFNDEF void cg_lab(mlabel *mlbl, char *do_emit)
 {
 	lab_tabent	lent;
 	mstr		glob_name;
@@ -315,11 +346,13 @@ void	cg_lab(mlabel *mlbl, char *do_emit)
 		if (do_emit)
 		{	/* Output (2nd) pass, emit the interesting information */
 			lent.lab_name.len = mlbl->mvname.len;
-			lent.lab_name.addr = (char *)(mlbl->mvname.addr - (char *)stringpool.base);
-											/* Offset into literal text pool */
+			lent.lab_name.addr = (0 < lent.lab_name.len)			/* Offset into literal text pool */
+				? (char *)(mlbl->mvname.addr - (char *)stringpool.base) : NULL;
 			lent.LABENT_LNR_OFFSET = (lnr_tabent *)(SIZEOF(lnr_tabent) * mlbl->ml->line_number);
 											/* Offset into lnr table */
 			lent.has_parms = (NO_FORMALLIST != mlbl->formalcnt);		/* Flag to indicate any formallist */
+			GTM64_ONLY(lent.filler = 0);					/* Remove garbage due so hashes well */
+			UNICODE_ONLY(lent.lab_name.char_len = 0);			/* .. ditto .. */
 			emit_immed((char *)&lent, SIZEOF(lent));
 		} else
 		{	/* 1st pass, do the definition but no emissions */
diff --git a/sr_unix/obj_file.c b/sr_unix/obj_file.c
index eaa3b6c..a61710d 100644
--- a/sr_unix/obj_file.c
+++ b/sr_unix/obj_file.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -28,6 +28,7 @@
 #include "gtmio.h"
 #include "mmemory.h"
 #include "obj_file.h"
+#include "mmrhash.h"
 
 GBLREF char		object_file_name[];
 GBLREF short		object_name_len;
@@ -51,32 +52,35 @@ static char			emit_buff[OBJ_EMIT_BUF_SIZE];	/* buffer for emit output */
 static int			emit_buff_used;			/* number of chars in emit_buff */
 static int			symcnt;
 static struct rel_table		*link_rel, *link_rel_end;	/* Linkage relocation entries.  */
-static struct linkage_entry	*linkage_first, *linkage_last;
-static struct sym_table		*symbols;
 
-void	emit_link_reference(int4 refoffset, mstr *name);
+static int tmpcnt;
 
-void	drop_object_file(void)
+error_def(ERR_OBJFILERR);
+error_def(ERR_STRINGOFLOW);
+
+STATICFNDCL void emit_link_reference(int4 refoffset, mstr *name);
+
+/* Routine to clear/delete the existing object file (used to delete existing temporary object file name
+ * on an error.
+ */
+void drop_object_file(void)
 {
 	int	rc;
 
         if (0 < object_file_des)
         {
 		UNLINK(object_file_name);
-		CLOSEFILE_RESET(object_file_des, rc);	/* resets "object_file_des" to FD_INVALID */
+		CLOSE_OBJECT_FILE(object_file_des, rc);		/* Resets "object_file_des" to FD_INVALID */
         }
 }
 
-error_def(ERR_OBJFILERR);
-error_def(ERR_STRINGOFLOW);
-
 /*
  *	emit_link_reference
  *
  *	Description: If not already defined, create relocation entry for
  *                   a linkage table entry to be resolved later.
  */
-void	emit_link_reference(int4 refoffset, mstr *name)
+STATICFNDEF void emit_link_reference(int4 refoffset, mstr *name)
 {
 	struct sym_table	*sym;
 	struct rel_table	*newrel;
@@ -86,7 +90,7 @@ void	emit_link_reference(int4 refoffset, mstr *name)
 	if ((N_TEXT | N_EXT) != sym->n.n_type)
 	{
 		newrel = (struct rel_table *)mcalloc(SIZEOF(struct rel_table));
-		newrel->next = (struct rel_table *)0;
+		newrel->next = NULL;
 		newrel->resolve = 0;
 		newrel->r.r_address = refoffset;
 		newrel->r.r_symbolnum = 0;
@@ -101,16 +105,17 @@ void	emit_link_reference(int4 refoffset, mstr *name)
 	}
 }
 
-
 /*
  *	emit_immed
  *
  *	Args:  buffer of executable code, and byte count to be output.
  */
-void	emit_immed(char *source, uint4 size)
+void emit_immed(char *source, uint4 size)
 {
-	short int 	write;
+	int4 	write;
 
+	if (0 == size)
+		return;			/* Not sure why but this does happen */
 	if (run_time)
 	{
 		if (!IS_STP_SPACE_AVAILABLE_PRO(size))
@@ -120,7 +125,7 @@ void	emit_immed(char *source, uint4 size)
 	} else
 	{
 		DEBUG_ONLY(obj_bytes_written += size);
-		while (size > 0)
+		while (0 < size)
 		{
 			write = SIZEOF(emit_buff) - emit_buff_used;
 			write = size < write ? size : write;
@@ -134,16 +139,20 @@ void	emit_immed(char *source, uint4 size)
 	}
 }
 
-
 /*
  *	buff_emit
  *
  *	Output partially or completely filled buffer
  */
-void	buff_emit(void)
+void buff_emit(void)
 {
 	int	stat;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
+	/* Accumulate object code piece in the object hash with progressive murmurhash call */
+	tmpcnt++;
+	gtmmrhash_128_ingest(TADR(objhash_state), emit_buff, emit_buff_used);
 	DOWRITERC(object_file_des, emit_buff, emit_buff_used, stat);
 	if (0 != stat)
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat);
@@ -155,7 +164,7 @@ void	buff_emit(void)
  *
  * 	Flush the contents of emit_buff to the file.
  */
-void	buff_flush(void)
+void buff_flush(void)
 {
 	if (emit_buff_used)
 		buff_emit();
@@ -176,13 +185,15 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 	struct sym_table	*sym, *sym1, *newsym;
 	stringkey		symkey;
 	ht_ent_str		*syment;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	usehtab = (SYM_HASH_CUTOVER < symcnt);
 	DEBUG_ONLY(syment = NULL);
 	if (!usehtab)
-	{	/* "Brute force" version of lookup for now */
+	{	/* "Brute force" version of lookup for now (until SYM_HASH_CUTOVER symbols defined) */
 		assert(NULL == compsyms_hashtab || NULL == compsyms_hashtab->base);
-		sym = symbols;
+		sym = TREF(defined_symbols);
 		sym1 = NULL;
 		while (sym)
 		{	/* Consider this a match only if type is N_EXT. If we are inserting an external reference symbol
@@ -190,7 +201,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 			 * (N_EXT) entry so that the symbol table is correctly formed.
 			 */
 			if ((0 >= (cmp = memvcmp(name->addr, (int)name->len, &sym->name[0], sym->name_len - 1)))
-				&& (N_EXT == sym->n.n_type))
+			    && (N_EXT == sym->n.n_type))
 				break;
 			sym1 = sym;
 			sym = sym->next;
@@ -198,11 +209,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 		if (!cmp && sym)
 			return sym;
 	} else
-	{	/* Hashtable lookup -- Note use of hashtab_mname for this is somewhat overloading the usage since there
-		   are compound symbols of the form "routine"."label" which can exceed the typical size of an mname but
-		   since mnames are just addr/length pairs at the definition level, this works for us and is easier than
-		   defining a new hashtable type identical to the mname hash in all but name.
-		*/
+	{	/* Hashtable lookup  */
 		if (!compsyms_hashtab)
 		{	/* Allocate if not allocated yet */
 			compsyms_hashtab = (hash_table_str *)malloc(SIZEOF(hash_table_str));
@@ -212,7 +219,7 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 		{	/* Need to initialize hash table and load it with the elements so far */
 			init_hashtab_str(compsyms_hashtab, SYM_HASH_CUTOVER * 2, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
 			assert(compsyms_hashtab->base);
-			for (sym = symbols; sym; sym = sym->next)
+			for (sym = TREF(defined_symbols); sym; sym = sym->next)
 			{
 				if (N_EXT != sym->n.n_type)	/* Consider this a match only if type is N_EXT. See comment above */
 					continue;
@@ -236,7 +243,6 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 			return sym;
 		}
 	}
-
 	/* Didn't find it in existing symbols; create new symbol.  */
 	newsym = (struct sym_table *)mcalloc(SIZEOF(struct sym_table) + name->len);
 	newsym->name_len = name->len + 1;
@@ -244,22 +250,22 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 	newsym->name[name->len] = 0;
 	newsym->n.n_type = N_EXT;
 	if (GTM_CODE == psect)
-		newsym->n.n_type |= N_TEXT;	/* if symbol is in GTM_CODE, it is defined */
+		newsym->n.n_type |= N_TEXT;	/* If symbol is in GTM_CODE, it is defined */
 	else
-		lnkrel_cnt++;	/* otherwise it's external (only one reference in linkage Psect) */
+		lnkrel_cnt++;		/* Otherwise it's external (only one reference in linkage Psect) */
 	newsym->resolve = 0;
-	newsym->linkage_offset = -1;	/* don't assign linkage Psect offset unless it's used */
+	newsym->linkage_offset = -1;	/* Don't assign linkage Psect offset unless it's used */
 	if (!usehtab)
 	{	/* Brute force -- add into the queue where the test failed (keeping sorted) */
 		newsym->next = sym;
 		if (sym1)
 			sym1->next = newsym;
 		else
-			symbols = newsym;
+			TREF(defined_symbols) = newsym;
 	} else
 	{	/* Hashtab usage -- add at beginning .. easiest since sorting doesn't matter for future lookups */
-		newsym->next = symbols;
-		symbols = newsym;
+		newsym->next = TREF(defined_symbols);
+		TREF(defined_symbols) = newsym;
 		assert(syment);
 		syment->value = newsym;
 	}
@@ -268,23 +274,26 @@ struct sym_table *define_symbol(unsigned char psect, mstr *name)
 	return newsym;
 }
 
-
-void	resolve_sym (void)
+/* Routine to resolve all the symbols of a given name to the same symbol number to associate relocation table
+ * entries together properly so all references for a given name associate to the same linkage table entry.
+ */
+void resolve_sym (void)
 {
 	uint4			symnum;
 	struct sym_table	*sym;
 	struct rel_table	*rel;
+	DCL_THREADGBL_ACCESS;
 
-	for (sym = symbols, symnum = 0; sym; sym = sym->next, symnum++)
+	SETUP_THREADGBL_ACCESS;
+	for (sym = TREF(defined_symbols), symnum = 0; sym; sym = sym->next, symnum++)
 	{
 		for (rel = sym->resolve; rel; rel = rel->resolve)
 			rel->r.r_symbolnum = symnum;
 	}
 }
 
-
 /* Output the relocation table for the linkage section */
-void	output_relocation (void)
+void output_relocation (void)
 {
 	struct rel_table	*rel;
 
@@ -292,16 +301,17 @@ void	output_relocation (void)
 		emit_immed((char *)&rel->r, SIZEOF(rel->r));
 }
 
-
 #ifdef DEBUG
 /* Size that output_symbol() below will eventually generate -- used to verify validity of OUTPUT_SYMBOL_SIZE macro */
-int	output_symbol_size(void)
+int output_symbol_size(void)
 {
 	uint4			string_length;
 	struct sym_table	*sym;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	string_length = SIZEOF(int4);
-	sym = symbols;
+	sym = TREF(defined_symbols);
 	while (sym)
 	{
 		string_length += sym->name_len;
@@ -311,19 +321,20 @@ int	output_symbol_size(void)
 }
 #endif
 
-
 /* Symbol string table output. Consists of a series of null terminated
-   strings in symbol number order.
-*/
-void	output_symbol(void)
+ * strings in symbol number order.
+ */
+void output_symbol(void)
 {
 	uint4			string_length;
 	struct sym_table	*sym;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	string_length = SIZEOF(int4) + sym_table_size;
 	assert(string_length == output_symbol_size());
 	emit_immed((char *)&string_length, SIZEOF(string_length));
-	sym = symbols;
+	sym = TREF(defined_symbols);
 	while (sym)
 	{
 		emit_immed((char *)&sym->name[0], sym->name_len);
@@ -331,40 +342,43 @@ void	output_symbol(void)
 	}
 }
 
-
 /*
  *	obj_init
  *
  *	Description:	Initialize symbol list, relocation information, linkage Psect list, linkage_size.
  */
-void	obj_init(void)
+void obj_init(void)
 {
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
 	lnkrel_cnt = symcnt = 0;
 	link_rel = link_rel_end = NULL;
-	symbols = NULL;
+	TREF(defined_symbols) = NULL;
+	TREF(linkage_first) = NULL;
+	TREF(linkage_last) = NULL;
 	sym_table_size = 0;
-
-	linkage_first = linkage_last = NULL;
-	linkage_size = MIN_LINK_PSECT_SIZE;	/* minimum size of linkage Psect, assuming no references from generated code */
-
+	linkage_size = MIN_LINK_PSECT_SIZE;	/* Minimum size of linkage Psect, assuming no references from generated code */
+   tmpcnt = 0;
 	return;
 }
 
-
 /*
  *	comp_linkages
  *
  *	Description: Define the symbols and relocation entries we will need to create
  *		     the linkage section when this module is linked in.
  */
-void	comp_linkages(void)
+void comp_linkages(void)
 {
 	mstr			name;
 	struct linkage_entry	*linkagep;
+	DCL_THREADGBL_ACCESS;
 
-	for (linkagep = linkage_first; NULL != linkagep; linkagep = linkagep->next)
+	SETUP_THREADGBL_ACCESS;
+	for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
 	{
-		name.len = linkagep->symbol->name_len - 1;	/* don't count '\0' terminator */
+		name.len = linkagep->symbol->name_len - 1;	/* Don't count '\0' terminator */
 		name.addr = (char *)&linkagep->symbol->name[0];
 		emit_link_reference(linkagep->symbol->linkage_offset, &name);
 	}
@@ -372,16 +386,19 @@ void	comp_linkages(void)
 	return;
 }
 
-
-void	emit_literals(void)
+void emit_literals(void)
 {
-	uint4		offset, padsize;
-	mliteral	*p;
+	mstr			name;
+	uint4			offset, padsize;
+	mliteral		*p;
+	struct linkage_entry	*linkagep;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	/* emit the literal text pool which includes the source file path and routine name */
 	offset = (uint4)(stringpool.free - stringpool.base);
 	emit_immed((char *)stringpool.base, offset);
-	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of source path on NATIVE_WSIZE boundary.*/
+	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns literal area on NATIVE_WSIZE boundary */
 	if (padsize)
 	{
 		emit_immed(PADCHARS, padsize);
@@ -389,7 +406,7 @@ void	emit_literals(void)
 	}
 	emit_immed(source_file_name, source_name_len);
 	offset += source_name_len;
-	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of routine_name on NATIVE_WSIZE boundary.*/
+	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns routine_name on NATIVE_WSIZE boundary */
 	if (padsize)
 	{
 		emit_immed(PADCHARS, padsize);
@@ -397,15 +414,43 @@ void	emit_literals(void)
 	}
 	emit_immed(routine_name.addr, routine_name.len);
 	offset += routine_name.len;
-	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits aligns the start of literal area on NATIVE_WSIZE boundary.*/
+	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns extern symbols on NATIVE_WSIZE boundary */
 	if (padsize)
 	{
 		emit_immed(PADCHARS, padsize);
 		offset += padsize;
 	}
+	/* Emit the names associated with the linkage table */
+	for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+	{
+		emit_immed((char *)linkagep->symbol->name, linkagep->symbol->name_len - 1);
+		offset += linkagep->symbol->name_len - 1;
+		padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE)); /* comp_lits() aligns extern symbols on NATIVE_WSIZE boundary */
+		if (padsize)
+		{
+			emit_immed(PADCHARS, padsize);
+			offset += padsize;
+		}
+	}
 	assert(offset == lits_text_size);
-
-	/* emit the literal mval list */
+	/* Emit the linkage name mstr table (never relocated - always offset/length pair). Same index as linkage table */
+	offset = 0;
+	for (linkagep = TREF(linkage_first); NULL != linkagep; linkagep = linkagep->next)
+	{
+		name.char_len = 0;				/* No need for this length */
+		name.len = linkagep->symbol->name_len - 1;	/* Don't count '\0' terminator */
+		name.addr = (char *)linkagep->lit_offset;
+		emit_immed((char *)&name, SIZEOF(mstr));
+		offset += SIZEOF(mstr);
+	}
+	padsize = (uint4)(PADLEN(offset, NATIVE_WSIZE));
+	if (padsize)
+	{
+		emit_immed(PADCHARS, padsize);
+		offset += padsize;
+	}
+	assert(0 == (uint4)(PADLEN(offset, NATIVE_WSIZE)));
+	/* Emit the literal mval list (also aligned by comp_lits() on NATIVE_WSIZE boundary */
 	offset = 0;
  	dqloop(&literal_chain, que, p)
 	{
@@ -416,13 +461,15 @@ void	emit_literals(void)
 		else
 			p->v.str.addr = NULL;
 		p->v.fnpc_indx = (unsigned char)-1;
+		if (!(MV_UTF_LEN & p->v.mvtype))
+			p->v.str.char_len = 0;
+		assert(MAX_STRLEN >= p->v.str.char_len);
 		emit_immed((char *)&p->v, SIZEOF(p->v));
 		offset += SIZEOF(p->v);
 	}
 	assert (offset == lits_mval_size);
 }
 
-
 /*
  *	find_linkage
  *
@@ -430,13 +477,14 @@ void	emit_literals(void)
  *
  *	Description:	Returns the offset into the linkage Psect of a global symbol.
  */
-int4	find_linkage(mstr* name)
+int4 find_linkage(mstr* name)
 {
 	struct linkage_entry	*newlnk;
 	struct sym_table	*sym;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	sym = define_symbol(GTM_LITERALS, name);
-
 	if (-1 == sym->linkage_offset)
 	{
 		/* Add new linkage psect entry at end of list.  */
@@ -445,18 +493,17 @@ int4	find_linkage(mstr* name)
 		newlnk = (struct linkage_entry *)mcalloc(SIZEOF(struct linkage_entry));
 		newlnk->symbol = sym;
 		newlnk->next = NULL;
-		if (NULL == linkage_first)
-			linkage_first = newlnk;
-		if (NULL != linkage_last)
-			linkage_last->next = newlnk;
-		linkage_last = newlnk;
+		if (NULL == TREF(linkage_first))
+			TREF(linkage_first) = newlnk;
+		if (NULL != TREF(linkage_last))
+			(TREF(linkage_last))->next = newlnk;
+		TREF(linkage_last) = newlnk;
 
 		linkage_size += SIZEOF(lnk_tabent);
 	}
 	return sym->linkage_offset;
 }
 
-
 /*
  *	literal_offset
  *
diff --git a/sr_unix/obj_filesp.h b/sr_unix/obj_filesp.h
index 02890a9..9f8a96e 100644
--- a/sr_unix/obj_filesp.h
+++ b/sr_unix/obj_filesp.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -16,6 +16,7 @@ typedef struct linkage_entry
 {
 	struct linkage_entry	*next;
 	struct sym_table	*symbol;
+	size_t			lit_offset;	/* Offset into literal string pool where string name was stored */
 } linkage_entry;
 
 struct sym_table *define_symbol(unsigned char psect, mstr *name);
diff --git a/sr_unix/obj_fileu.c b/sr_unix/obj_fileu.c
new file mode 100644
index 0000000..6037967
--- /dev/null
+++ b/sr_unix/obj_fileu.c
@@ -0,0 +1,147 @@
+/****************************************************************
+ *								*
+ *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made available	*
+ *	under a license.  If you do not know the terms of	*
+ *	the license, please stop and do not read further.	*
+ *								*
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/types.h>
+#include "gtm_stat.h"
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+#include "gtm_limits.h"
+
+#include "cmd_qlf.h"
+#include "gtmio.h"
+#include "parse_file.h"
+#include <rtnhdr.h>
+#include "obj_file.h"
+
+GBLREF command_qualifier	cmd_qlf;
+GBLREF char			object_file_name[];
+GBLREF short			object_name_len;
+GBLREF mident			module_name;
+
+#define MKSTEMP_MASK		"XXXXXX"
+#define MAX_MKSTEMP_RETRIES	100
+
+error_def(ERR_FILEPARSE);
+error_def(ERR_OBJFILERR);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+
+/********************************************************************************************************************************
+ *
+ * While these routines might rightly belong in obj_file.c, since these routines are needed both in sr_unix and in sr_unix_nsb,
+ * it was decided to create this module to share routines that are the same across both unix and linux-i386 so the routines only
+ * need to exist in one place.
+ *
+ ********************************************************************************************************************************/
+
+/* Routine to create a temporary object file. This file is created in the directory it is supposed to reside in but is created
+ * with a temporary name. When complete, it is renamed to what it was meant to be replacing the previous version.
+ *
+ * Parameters:
+ *
+ *   object_fname     - Character array of the object path/name.
+ *   object_fname_len - Length of that array in bytes.
+ *
+ * Return value:
+ *   File descriptor for the open object file.
+ */
+int mk_tmp_object_file(const char *object_fname, int object_fname_len)
+{
+	int	fdesc, status, umask_creat, umask_orig, retry;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	/* Make sure room in buffer for addition of unique-ifying MKSTEMP_MASK on end of file name */
+	if ((object_fname_len + SIZEOF(MKSTEMP_MASK) - 1) > TLEN(tmp_object_file_name))
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_OBJFILERR, 2, object_fname_len, object_fname, ERR_TEXT,
+			      2, RTS_ERROR_TEXT("Object file name exceeds buffer size"));
+	/* The mkstemp() routine is known to bogus-fail for no apparent reason at all especially on AIX 6.1. In the event
+	 * this shortcoming plagues other platforms as well, we add a low-cost retry wrapper.
+	 */
+	retry = MAX_MKSTEMP_RETRIES;
+	do
+	{
+		memcpy(TADR(tmp_object_file_name), object_fname, object_fname_len);
+		/* Note memcpy() below purposely includes null terminator */
+		memcpy(TADR(tmp_object_file_name) + object_fname_len, MKSTEMP_MASK, SIZEOF(MKSTEMP_MASK));
+		fdesc = mkstemp(TADR(tmp_object_file_name));
+	} while ((-1 == fdesc) && (EEXIST == errno) && (0 < --retry));
+	if (FD_INVALID == fdesc)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_fname_len, object_fname, errno);
+	umask_orig = umask(000);	/* Determine umask (destructive) */
+	(void)umask(umask_orig);	/* Reset umask */
+	umask_creat = 0666 & ~umask_orig;
+	/* Change protections to be those generated by previous versions. In some future version, the permissions may
+	 * become tied to the permissions of the source but this works for now.
+	 */
+	status = FCHMOD(fdesc, umask_creat);
+	if (-1 == status)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fchmod()"), CALLFROM, errno);
+        return fdesc;
+}
+
+/* Routine to rename the most recent temporary object file (name stored in threadgbl tmp_object_file_name) to the name
+ * passed in via parameter.
+ *
+ * Parameters:
+ *   object_fname         - non-temporary name of object file
+ *
+ * Global input:
+ *   tmp_object_file_name - private/unique file created by mkstemp() in routine above.
+ */
+void rename_tmp_object_file(const char *object_fname)
+{
+	int	status;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	status = rename(TADR(tmp_object_file_name), object_fname);
+	if (-1 == status)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("rename()"), CALLFROM, errno);
+}
+
+/* Routine to determine and initialize the fully qualified object name and path.
+ *
+ * Parameters:
+ *   - none
+ *
+ * Global inputs:
+ *   cmd_qlf.object_file - value from -object= option
+ *   module_name         - routine name
+ * Global outputs:
+ *   object_file_name    - full path of object file
+ *   object_name_len     - length of full path (not including null terminator)
+ */
+void init_object_file_name(void)
+{
+	int		status, rout_len;
+	char		obj_name[SIZEOF(mident_fixed) + 5];
+	mstr		fstr;
+	parse_blk	pblk;
+
+	memset(&pblk, 0, SIZEOF(pblk));
+	pblk.buffer = object_file_name;
+	pblk.buff_size = MAX_FBUFF;
+	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 = (int)module_name.len;
+	memcpy(&obj_name[0], module_name.addr, rout_len);
+	memcpy(&obj_name[rout_len], DOTOBJ, SIZEOF(DOTOBJ));    /* Includes null terminator */
+	pblk.def1_size = rout_len + SIZEOF(DOTOBJ) - 1;         /* Length does not include null terminator */
+	pblk.def1_buf = obj_name;
+	status = parse_file(&fstr, &pblk);
+	if (0 == (status & 1))
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status);
+	object_name_len = pblk.b_esl;
+	object_file_name[object_name_len] = '\0';
+}
diff --git a/sr_unix/ojchildioclean.c b/sr_unix/ojchildioclean.c
index 24a28f3..b85fce7 100644
--- a/sr_unix/ojchildioclean.c
+++ b/sr_unix/ojchildioclean.c
@@ -30,7 +30,6 @@
 #endif
 #include <rtnhdr.h>
 #include "relinkctl.h"
-#include "zhist.h"
 
 GBLREF	int			mutex_sock_fd;
 
@@ -77,7 +76,7 @@ void ojchildioclean(void)
 #endif
 	/* Since we are removing artifacts from the originating process (which still has these files open), there is
 	 * no need to decrement the counts (they will increase if this process links the same files). The FALSE
-	 * argument prevents the count from being modified in this cleanup.
+	 * argument prevents the relinkctl-attach & rtnobj-reference counts from being modified in this cleanup.
 	 */
-	USHBIN_ONLY(relinkctl_rundown(FALSE));
+	ARLINK_ONLY(relinkctl_rundown(FALSE, FALSE));
 }
diff --git a/sr_unix/ojchildparms.c b/sr_unix/ojchildparms.c
index a99afb0..ea4a9e6 100644
--- a/sr_unix/ojchildparms.c
+++ b/sr_unix/ojchildparms.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -27,16 +27,39 @@
 #include "op.h"		/* for op_nullexp() */
 #include "io.h"
 #include "iosocketdef.h"
-
+#include "indir_enum.h"
 #include <errno.h>
+#include "gtm_maxstr.h"
+#include "job_addr.h"
+#include "gtmci.h"
+#include "cache.h"
+#include "hashtab_objcode.h"
+#include "gtmio.h"
+
+GBLREF spdesc			stringpool;
+GBLREF io_log_name		*dollar_principal;
+GBLREF io_pair			io_std_device;
+GBLREF unsigned char		*source_buffer;
+GBLREF int4			aligned_source_buffer[];
+GBLREF stack_frame		*frame_pointer;
+GBLREF hash_table_objcode	cache_table;
+#ifdef DEBUG
+GBLREF unsigned char		*msp;
+static unsigned char		*save_msp;
+#endif
+static	char			*sp;
 
-GBLREF	spdesc		stringpool;
-GBLREF	io_log_name	*dollar_principal;
-GBLREF	io_pair		io_std_device;
+STATICFNDCL void receive_child_locals_init(char **local_buff, mval **comm_stack_ptr);
+STATICFNDCL void receive_child_locals_finalize(char **local_buff);
+/* All other platforms use this much faster direct return */
+void gtm_levl_ret_code(void);
 
 error_def(ERR_CLOSEFAIL);
 error_def(ERR_JOBSETUP);
 error_def(ERR_STRINGOFLOW);
+error_def(ERR_JOBLVN2LONG);
+
+#define MAX_COMM_FRAME	5
 
 /*
  * ------------------------------------------------
@@ -44,9 +67,8 @@ error_def(ERR_STRINGOFLOW);
  * parameter structure
  * ------------------------------------------------
  */
-void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
+STATICFNDEF void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
 {
-	char			*sp, *parmbuf;
 	char			parm_string[8];
 	int4			argcnt, i;
 	int			setup_fd;
@@ -59,29 +81,30 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
 	job_buffer_size_msg	buffer_size;
 	d_socket_struct		*dsocketptr;
 	socket_struct		*socketptr;
+	char			*local_buff = NULL;
+	int			comm_arg_count;
+	mval			*command_str[MAX_COMM_FRAME];
 
-	assertpro((sp = GETENV(CHILD_FLAG_ENV)) && sp[0]);	/* note assignment */
+	if ((NULL == sp) && (!((sp = GETENV(CHILD_FLAG_ENV)) && sp[0]))) /* note assignment */
+		return;
 	setup_fd = (int)ATOL(sp);
-
-	g_args->callargs = 0;
-
+	if (NULL != g_args)
+		g_args->callargs = 0;
 	while(!setup_done)
 	{
-		RECV(setup_fd, &setup_op, SIZEOF(setup_op), 0, rc);
+		DOREADRC(setup_fd, &setup_op, SIZEOF(setup_op), rc);
 		if (rc < 0)
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("setup operation"), errno, 0);
-		assert(SIZEOF(setup_op) == rc);
 		switch(setup_op)
 		{
 		case job_done:
+		case local_trans_done:
 			setup_done = TRUE;
 			break;
-
 		case job_set_params:
-			RECV(setup_fd, &params, SIZEOF(params), 0, rc);
+			DOREADRC(setup_fd, &params, SIZEOF(params), rc);
 			if (rc < 0)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("job parameters"), errno, 0);
-			assert(SIZEOF(params) == rc);
 
 			jparms->directory.len = params.directory_len;
 			jparms->gbldir.len = params.gbldir_len;
@@ -134,14 +157,11 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
 				jparms->label.addr = malloc(jparms->label.len + 1);
 				memcpy(jparms->label.addr, params.label, jparms->label.len + 1);
 			}
-
 			break;
-
 		case job_set_parm_list:
-			RECV(setup_fd, &arg_count, SIZEOF(arg_count), 0, rc);
+			DOREADRC(setup_fd, &arg_count, SIZEOF(arg_count), rc);
 			if (rc < 0)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("argument count"), errno, 0);
-			assert(SIZEOF(arg_count) == rc);
 			g_args->callargs = arg_count + 4;
 			g_args->truth = 1;
 			g_args->retval = 0;
@@ -149,11 +169,10 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
 			g_args->argcnt = arg_count;
 			for (i = 0; i < arg_count; i++)
 			{
-				RECV(setup_fd, &arg_msg, SIZEOF(arg_msg), 0, rc);
+				DOREADRC(setup_fd, &arg_msg, SIZEOF(arg_msg), rc);
 				if (rc < 0)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("argument"),
 							errno, 0);
-				assert(SIZEOF(arg_msg) == rc);
 				if (0 > arg_msg.len)
 					g_args->argval[i] = op_nullexp();	/* negative len indicates null arg */
 				else
@@ -177,27 +196,117 @@ void ojchildparms(job_params_type *jparms, gcall_args *g_args, mval *arglst)
 			assertpro(-1 != dsocketptr->current_socket);
 			assertpro(dsocketptr->current_socket < dsocketptr->n_socket);
 			socketptr = dsocketptr->socket[dsocketptr->current_socket];
-
-			RECV(setup_fd, &buffer_size, SIZEOF(buffer_size), 0, rc);
+			DOREADRC(setup_fd, &buffer_size, SIZEOF(buffer_size), rc);
 			if (rc < 0)
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("input buffer size"),
-						errno, 0);
-			assert(SIZEOF(buffer_size) == rc);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+					      LEN_AND_LIT("input buffer size"), errno, 0);
 			assertpro(buffer_size <= DEFAULT_SOCKET_BUFFER_SIZE);
 			assertpro(buffer_size <= socketptr->buffer_size);
-
-			RECV(setup_fd, socketptr->buffer, buffer_size, 0, rc);
+			DOREADRC(setup_fd, socketptr->buffer, buffer_size, rc);
 			if (rc < 0)
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2, LEN_AND_LIT("input buffer"), errno, 0);
-			assert(buffer_size == rc);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+					      LEN_AND_LIT("input buffer"), errno, 0);
 			socketptr->buffered_length = buffer_size;
 			socketptr->buffered_offset = 0;
 			break;
-
+		case job_set_locals:
+			/* We should get here from the second ojchildparams() call only */
+			assert(NULL == jparms);
+			if (NULL == local_buff)
+			{	/* Initializations to receive the local vars */
+				receive_child_locals_init(&local_buff, command_str);
+				comm_arg_count = 0;
+			}
+			command_str[comm_arg_count]->mvtype = MV_STR;
+			command_str[comm_arg_count]->str.addr = local_buff;
+			DOREADRC(setup_fd, &buffer_size, SIZEOF(buffer_size), rc);
+			if (rc < 0)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+					      LEN_AND_LIT("receive buffer size"), errno, 0);
+			if (buffer_size > MAX_STRLEN)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JOBLVN2LONG, 2, MAX_STRLEN, buffer_size);
+			assert(buffer_size > 0);
+			DOREADRC(setup_fd, local_buff, buffer_size, rc);
+			if (rc < 0)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBSETUP, 2,
+					      LEN_AND_LIT("local fragment"), errno, 0);;
+			assert((NULL != command_str[comm_arg_count]->str.addr) && (0 != buffer_size));
+			command_str[comm_arg_count]->str.len = buffer_size;
+			s2pool(&command_str[comm_arg_count]->str);
+			op_commarg(command_str[comm_arg_count], indir_set);
+			comm_arg_count++;
+			if (MAX_COMM_FRAME == comm_arg_count)
+			{	/* grouping op_commargs() for one dm_start() is faster */
+				dm_start();
+				comm_arg_count = 0;
+			}
+			break;
 		default:
 			assertpro(FALSE && setup_op);
 		}
 	}
-	if ((rc = close(setup_fd)) < 0)
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, setup_fd, errno, 0);
+	if (NULL != local_buff)
+	{
+		if (comm_arg_count != 0)
+			dm_start();
+		receive_child_locals_finalize(&local_buff);
+	}
+	/* Keep the pipe alive until local transfer is done which is done at the second call to this function */
+	if (local_trans_done == setup_op)
+		if ((rc = close(setup_fd)) < 0)
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, setup_fd, errno, 0);
+}
+
+STATICFNDEF void receive_child_locals_init(char **local_buff, mval **command_str)
+{
+	rhdtyp	*base_addr;
+	int i;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	assert(active_ch == ctxt);
+	assert(ctxt == chnd);
+	DEBUG_ONLY(save_msp = msp);
+	*local_buff = malloc(MAX_STRLEN);
+	source_buffer = malloc(MAX_STRLEN + 2);
+	TREF(max_advancewindow_line) = MAX_STRLEN + 1;
+	/* Get space from the stack to save the command strings before putting the base stack frame This must be done first (before
+	 * putting the base frame) so that dm_start does not unintentionally pop strings off the stack
+	 */
+	for (i = 0; i < MAX_COMM_FRAME; i++)
+	{
+		PUSH_MV_STENT(MVST_MVAL);
+		command_str[i] = &mv_chain->mv_st_cont.mvs_mval;
+	}
+	/* Setup the base frame */
+	base_addr = make_cimode();
+	frame_pointer->flags |= SFF_IMPLTSTART_CALLD; 	/* Do not return to this frame via MUM_TSTART */
+	base_frame(base_addr);
+	/* Finish base frame initialization - reset mpc/context to return to us without unwinding base frame */
+	frame_pointer->type |= SFT_TRIGR;
+	frame_pointer->mpc = CODE_ADDRESS(gtm_levl_ret_code);
+	frame_pointer->ctxt = GTM_CONTEXT(gtm_levl_ret_code);
+}
+
+STATICFNDEF void receive_child_locals_finalize(char **local_buff)
+{
+	int i;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	/* Unwind the base frame */
+	op_unwind();
+	frame_pointer = *(stack_frame**)msp;
+	msp += SIZEOF(stack_frame *);           /* Remove frame save pointer from stack */
+	free(*local_buff);
+	free(source_buffer);
+	/* Reset the source buffer */
+	TREF(max_advancewindow_line) = MAX_SRCLINE;
+	source_buffer = (unsigned char *)aligned_source_buffer;
+	/* Return the space saved for command strings */
+	i = MAX_COMM_FRAME;
+	while (i--)
+		POP_MV_STENT();
+	ctxt = active_ch = chnd;		/* Clear extra condition handlers added by dm_start()s */
+	assert(save_msp == msp);
 }
diff --git a/sr_unix/ojparams.c b/sr_unix/ojparams.c
index 9600faa..8fe0c16 100644
--- a/sr_unix/ojparams.c
+++ b/sr_unix/ojparams.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -63,6 +63,7 @@ void ojparams (char *p, job_params_type *job_params)
 	job_params->directory.addr = 0;
 	job_params->cmdline.len = 0;
 	job_params->cmdline.addr = 0;
+	job_params->passcurlvn = FALSE;
 
 		/* Process parameter list */
 	while (*p != jp_eol)
@@ -129,6 +130,9 @@ void ojparams (char *p, job_params_type *job_params)
 			}
 			break;
 
+		case jp_passcurlvn:
+			job_params->passcurlvn = TRUE;
+			break;
 		case jp_account:
 		case jp_detached:
 		case jp_image:
diff --git a/sr_unix/ojstartchild.c b/sr_unix/ojstartchild.c
index c3e2d09..7f8a967 100644
--- a/sr_unix/ojstartchild.c
+++ b/sr_unix/ojstartchild.c
@@ -43,18 +43,32 @@
 #include "compiler.h"
 #include "job_addr.h"
 #include "util.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
 #include "gtm_facility.h"
 #include "fileinfo.h"
 #include "gtmio.h"
 #include "fork_init.h"
+#include "rtnobj.h"
+#include "getjobnum.h"
+#include "zshow.h"
+#include "zwrite.h"
+#include "gtm_maxstr.h"
 
 GBLREF	bool			jobpid;	/* job's output files should have the pid appended to them. */
 GBLREF	volatile boolean_t	ojtimeout;
 GBLREF  boolean_t       	gtm_pipe_child;
 GBLREF	int			job_errno;
+GBLREF	zshow_out		*zwr_output;
+GBLREF	uint4			pat_everything[];
+GBLREF	mstr_len_t		sizeof_pat_everything;
+GBLREF	io_pair			io_curr_device;
 
 static  joberr_t		joberr = joberr_gen;
 static	int			pipe_fd;
+static	int			setup_fds[2];	/* socket pair for setup of final mumps process */
+static	pid_t			child_pid;
 
 #ifndef SYS_ERRLIST_INCLUDE
 /* currently either stdio.h or errno.h both of which are included above needed by TIMEOUT_ERROR in jobsp.h */
@@ -119,7 +133,7 @@ LITREF gtmImageName	gtmImageNames[];
 	kill(child_pid, SIGTERM);							\
 	joberr = joberr_io_setup_op_write;						\
 	job_errno = errno;								\
-	DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);		\
+	DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);			\
 	_exit(joberr);									\
 }
 
@@ -132,8 +146,18 @@ LITREF gtmImageName	gtmImageNames[];
 	_exit(joberr);									\
 }
 
+#ifdef AUTORELINK_SUPPORTED
+#define	RELINKCTL_RUNDOWN_MIDDLE_PARENT(NEED_RTNOBJ_SHM_FREE, RTNHDR)			\
+{											\
+	if (NEED_RTNOBJ_SHM_FREE)							\
+		rtnobj_shm_free(RTNHDR, LATCH_GRABBED_FALSE);				\
+	relinkctl_rundown(TRUE, FALSE);							\
+}
+#endif
+
 error_def(ERR_GTMDISTUNVERIF);
 error_def(ERR_JOBFAIL);
+error_def(ERR_JOBLVN2LONG);
 error_def(ERR_JOBPARTOOLONG);
 error_def(ERR_LOGTOOLONG);
 error_def(ERR_TEXT);
@@ -142,8 +166,9 @@ error_def(ERR_TEXT);
  * not want to run.
  */
 
-void job_term_handler(int sig);
-static int io_rename(job_params_msg *params, const int jobid);
+STATICFNDCL void job_term_handler(int sig);
+STATICFNDCL int io_rename(job_params_msg *params, const int jobid);
+STATICFNDCL void local_variable_marshalling(void);
 
 /* Middle process sets the entryref for the jobbed-off process by calling job_addr(). job_addr() internally calls op_zlink(). If
  * rts_error occurs when we are in the job_addr() function, the topmost condition handler inherited from parent process will be
@@ -154,11 +179,12 @@ static CONDITION_HANDLER(middle_child)
 {
 	int pipe_status;
 	START_CH(FALSE);
-	DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);
 	/* As of now, middle process could encounter rts_error only while setting entryref. Hence the following assert.
 	 * Do assert after write to prevent parent hang.
 	 */
 	assert(joberr == joberr_rtn);
+	ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(FALSE, NULL);)	/* decrement refcnts for relinkctl shm */
+	DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);
 	_exit(joberr);
 }
 
@@ -175,7 +201,7 @@ static CONDITION_HANDLER(grand_child)
  * successfully forked-off the job.
  */
 
-void job_term_handler(int sig)
+STATICFNDEF void job_term_handler(int sig)
 {
 		int ret;
 		int status;
@@ -195,7 +221,7 @@ void job_term_handler(int sig)
 			return;
 }
 
-static int io_rename(job_params_msg *params, const int jobid)
+STATICFNDEF int io_rename(job_params_msg *params, const int jobid)
 {
 	char path[MAX_STDIOE_LEN];
 
@@ -218,6 +244,76 @@ static int io_rename(job_params_msg *params, const int jobid)
 	return 0;
 }
 
+void ojmidchild_send_var(void)
+{
+	job_setup_op setup_op;
+	int rc, pipe_status;
+	job_buffer_size_msg buffer_size;
+
+	setup_op = job_set_locals;
+	SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
+	if (rc < 0)
+		SETUP_OP_FAIL();
+	buffer_size = zwr_output->ptr - zwr_output->buff;
+	/* Crop the ' ;*' string at the end of the aliases */
+	if (zwr_output->buff[buffer_size - 1] == '*' && zwr_output->buff[buffer_size - 2] == ';'
+	    && zwr_output->buff[buffer_size - 3] == ' ')
+		buffer_size -= 3;
+	assert(buffer_size > 0);
+	/* We must send the buffer_size regardless of its value. The child has its own check for size. It is going to terminate if
+	 * the size is excessive.
+	 */
+	SEND(setup_fds[0], &buffer_size, SIZEOF(buffer_size), 0, rc);
+	if (rc < 0)
+		SETUP_OP_FAIL();
+	if (buffer_size > MAX_STRLEN)
+	{
+		rc = ERR_JOBLVN2LONG;
+		DOWRITERC(pipe_fd, &rc, SIZEOF(rc), pipe_status);
+		/* No need to SIGTERM the child because child will issue a proper error message and quit */
+		_exit(joberr_io_setup_op_write);
+	}
+	SEND(setup_fds[0], zwr_output->buff, buffer_size, 0, rc);
+	if (rc < 0)
+		SETUP_OP_FAIL();
+	zwr_output->ptr = zwr_output->buff;
+	return;
+}
+
+STATICFNDEF void local_variable_marshalling(void)
+{
+	/* Setup buffer to write local variables one at a time */
+	zshow_out	output;
+	mval		pattern;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	memset(&output, 0, SIZEOF(output));
+	output.code = 'V';
+	output.type = ZSHOW_BUFF_ONLY;
+	/* Expanded MAXSTR_BUFF_DECL/MAXSTR_BUFF_INIT below because they are designed to handle the size of MAX_STRBUFF_INIT when we
+	 * really want is MAX_STRLEN The condition handler established within MAXSTR_BUFF_INIT is futile because any error we
+	 * encounter here is fatal
+	 */
+	output.buff = malloc(MAX_STRLEN);
+	output.size = MAX_STRLEN;
+	maxstr_stack_level++;
+	assert(maxstr_stack_level < MAXSTR_STACK_SIZE);
+	maxstr_buff[maxstr_stack_level].len = output.size;
+	maxstr_buff[maxstr_stack_level].addr = NULL;
+	output.ptr = output.buff;
+	TREF(midchild_send_locals) = TRUE;
+	pattern.str.addr = (char *)pat_everything;
+	pattern.str.len = sizeof_pat_everything;
+	pattern.mvtype = MV_STR;
+	lvzwr_init(zwr_patrn_mval, &pattern);
+	lvzwr_fini(&output, ZWRITE_END);
+	TREF(midchild_send_locals) = FALSE;
+	free(output.buff);
+	return;
+}
+
+
 /*
  * --------------------------------------------------------------------------------------------------------------------------------
  * The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the actual Job (J)
@@ -241,6 +337,7 @@ static int io_rename(job_params_msg *params, const int jobid)
 
 int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[])
 {
+	boolean_t		need_rtnobj_shm_free;
 	char			cbuff[TEMP_BUFF_SIZE], pbuff[TEMP_BUFF_SIZE], cmdbuff[TEMP_BUFF_SIZE];
 	char			tbuff[MAX_JOB_LEN], tbuff2[MAX_JOB_LEN], fname_buf[MAX_STDIOE_LEN];
 	char			*pgbldir_str;
@@ -249,34 +346,33 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 	int			wait_status, save_errno, kill_ret;
 	int			rc, dup_ret, in_fd;
 	int			status;
-	pid_t			child_pid, done_pid;
+	pid_t			done_pid;
 	job_parm		*jp;
-	rhdtyp			*base_addr;
+	rhdtyp			*rtnhdr;
 	struct sigaction	act, old_act;
 	int			pipe_status, env_len;
 	int			mproc_fds[2]; 	/* pipe between middle process and grandchild process */
 	int			decision;
-	int			setup_fds[2];	/* socket pair for setup of final mumps process */
 	job_setup_op		setup_op;
 	job_params_msg		params;
 	job_arg_count_msg	arg_count;
 	job_arg_msg		arg_msg;
 	job_buffer_size_msg	buffer_size;
-
-#ifdef	__osf__
-/* These must be O/S-compatible 64-bit pointers for OSF/1.  */
-#pragma	pointer_size (save)
-#pragma pointer_size (long)
-#endif
-
+#	ifdef	__osf__
+		/* These must be O/S-compatible 64-bit pointers for OSF/1.  */
+#		pragma	pointer_size (save)
+#		pragma pointer_size (long)
+#	endif
 	char		*c1, *c2, **c3;
 	char		*argv[4];
 	char		**env_ary, **env_ind;
 	char		**new_env_cur, **new_env_top, **old_env_cur, **old_env_top, *env_end;
+#	ifdef	__osf__
+#		pragma pointer_size (restore)
+#	endif
+	DCL_THREADGBL_ACCESS;
 
-#ifdef	__osf__
-#pragma pointer_size (restore)
-#endif
+	SETUP_THREADGBL_ACCESS;
 	/* Do the fork and exec but BEFORE that do a FFLUSH(NULL) to make sure any fclose (done in io_rundown
 	 * in the child process) does not affect file offsets in this (parent) process' file descriptors
 	 */
@@ -292,6 +388,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 		 * much hitch. If any error occurs during this, exit with appropriate status so the waiting parent can diagnose.
 		 */
 
+		getjobnum();	/* set "process_id" to a value different from parent. This is particularly needed for the
+				 * RELINKCTL_RUNDOWN_MIDDLE_PARENT macro since it does rtnobj_shm_free which deals with latches
+				 * that in turn rely on the "process_id" global variable reflecting the current pid.
+				 */
 		/* set to TRUE so any child process associated with a pipe device will know it is not the parent in iorm_close() */
 		gtm_pipe_child = TRUE;
 		joberr = joberr_gen;
@@ -371,11 +471,30 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
 			_exit(status);
 		}
-
+		/* Record the fact that this process is interested in the relinkctl files inherited from the parent by
+		 * incrementing the linkctl->hdr->nattached count. This is required by the relinkctl_rundown(TRUE, FALSE)
+		 * call done as part of the RELINKCTL_RUNDOWN_MIDDLE_PARENT macro in the middle child or the grandchild.
+		 * Do this BEFORE the call to job_addr. In case that does a relinkctl_attach of a new relinkctl file,
+		 * we would increment the counter automatically so dont want that to go through a double-increment.
+		 */
+		ARLINK_ONLY(relinkctl_incr_nattached());
 		joberr = joberr_rtn;
-		if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr))
+		/* We are the middle child. It is possible the below call to job_addr loads an object into shared memory
+		 * using "rtnobj_shm_malloc". In that case, as part of halting we need to do a "rtnobj_shm_free" to keep
+		 * the rtnobj reference counts in shared memory intact. The variable "need_rtnobj_shm_free" servers this purpose.
+		 * Note that we cannot safely call relinkctl_rundown since we do not want to decrement reference counts for
+		 * routines that have already been loaded by our parent process (which we inherited due to the fork) since
+		 * the parent process is the one that will do the decrement later. We should decrement the count only for
+		 * routines that we load ourselves. And the only one possible is due to the below call to "job_addr".
+		 * Note that the balancing decrement/free happens in the middle child until the grandchild is forked.
+		 * Once the grandchild fork succeeds, the grandchild is incharge of doing this cleanup. This flow is needed
+		 * so the decrement (and potential removal of rtnobj shmid) only happens AFTER when it is needed.
+		 */
+		if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&rtnhdr, &transfer_addr,
+			&need_rtnobj_shm_free))
 		{
 			DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 			_exit(joberr);
 		}
 
@@ -384,14 +503,16 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 		{
 			job_errno = errno;
 			DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 			_exit(joberr);
 		}
 
 		joberr = joberr_sp;
-		if (-1 == (rc = socketpair(AF_UNIX, SOCK_DGRAM, 0, setup_fds)))
+		if (-1 == (rc = socketpair(AF_UNIX, SOCK_STREAM, 0, setup_fds)))
 		{
 			job_errno = errno;
 			DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 			_exit(joberr);
 		}
 
@@ -430,7 +551,6 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 					_exit(joberr);
 				}
 			}
-
 			/* Inform grandchild that everything is properly set for it and it is ready to continue. */
 			decision = JOB_CONTINUE;
 			DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status);
@@ -442,13 +562,11 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 				DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
 				_exit(joberr);
 			}
-
 			/* send job parameters and arguments to final mumps process over setup socket */
 			setup_op = job_set_params;
 			SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
 			if (rc < 0)
 				SETUP_OP_FAIL();
-
 			params.directory_len = jparms->directory.len;
 			memcpy(params.directory, jparms->directory.addr, jparms->directory.len);
 			if (0 < jparms->gbldir.len)
@@ -484,17 +602,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			SEND(setup_fds[0], &params, SIZEOF(params), 0, rc);
 			if (rc < 0)
 				SETUP_DATA_FAIL();
-
 			setup_op = job_set_parm_list;
 			SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
 			if (rc < 0)
 				SETUP_OP_FAIL();
-
 			arg_count = argcnt;
 			SEND(setup_fds[0], &arg_count, SIZEOF(arg_count), 0, rc);
 			if (rc < 0)
 				SETUP_DATA_FAIL();
-
 			for (jp = jparms->parms;  jp ; jp = jp->next)
 			{
 				if (jp->parm->str.len > MAX_JOB_LEN - 2)
@@ -512,31 +627,37 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 				if (rc < 0)
 					SETUP_DATA_FAIL();
 			}
-
 			if (0 < jparms->input_prebuffer_size)
 			{
 				setup_op = job_set_input_buffer;
 				SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
 				if (rc < 0)
 					SETUP_OP_FAIL();
-
 				buffer_size = jparms->input_prebuffer_size;
 				SEND(setup_fds[0], &buffer_size, SIZEOF(buffer_size), 0, rc);
 				if (rc < 0)
 					SETUP_DATA_FAIL();
-
 				SEND(setup_fds[0], jparms->input_prebuffer, jparms->input_prebuffer_size, 0, rc);
 				if (rc < 0)
 					SETUP_DATA_FAIL();
 				/* input_prebuffer leaks, but the middle process is about to exit, so don't worry about it */
 			}
-
-			/* tell job to proceed */
 			setup_op = job_done;
 			SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
 			if (rc < 0)
 				SETUP_OP_FAIL();
-
+			/* Send the local variables */
+			if (jparms->passcurlvn)
+				local_variable_marshalling();
+			/* tell job to proceed */
+			setup_op = local_trans_done;
+			SEND(setup_fds[0], &setup_op, SIZEOF(setup_op), 0, rc);
+			if (rc < 0)
+				SETUP_OP_FAIL();
+			/* tell job to proceed but before that detach from relinkctl/rtnobj shared memory in case the grandchild
+			 * needs to remove those (due to linkctl->hdr->nattached being 0).
+			 */
+			ARLINK_ONLY(relinkctl_rundown(FALSE, FALSE));	/* do not decrement counters, just shmdt */
 			/* write child_pid into pipe to be read by parent process(P) for $ZJOB */
 			/* Ignore the status if this fails, as the child is already running, and there is likely not a parent
 			 * to report to.
@@ -547,21 +668,26 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 		/* This is now the grandchild process (actual Job process) -- an orphan as soon as the exit(EXIT_SUCCESS) above
 		 * occurs. Revert the condition handler established by middle process and establish its own condition handler */
 		REVERT;
+		getjobnum();	/* set "process_id" to a value different from parent (middle child). This is particularly needed
+				 * for the RELINKCTL_RUNDOWN_MIDDLE_PARENT macro since it does rtnobj_shm_free which deals with
+				 * latches that in turn rely on the "process_id" global variable reflecting the current pid.
+				 */
 		ESTABLISH_RET(grand_child, 0);
 		sigaction(SIGTERM, &old_act, 0);		/* restore the SIGTERM handler */
 		CLOSEFILE_RESET(mproc_fds[1], pipe_status);	/* resets "mproc_fds[0]" to FD_INVALID */
 		CLOSEFILE_RESET(setup_fds[0], pipe_status);	/* resets "setup_fds[0]" to FD_INVALID */
 		DOREADRC(mproc_fds[0], &decision, SIZEOF(decision), pipe_status);
 		if (pipe_status)	 /* We failed to read the communication from middle process */
+		{
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 	                rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
 						LEN_AND_LIT("Error reading from pipe"), errno);
-		else {
+		} else {
 			if (JOB_EXIT == decision)
 				exit(EXIT_SUCCESS);
 			assert(JOB_CONTINUE == decision);
 		}
 		CLOSEFILE_RESET(mproc_fds[0], pipe_status);	/* resets "mproc_fds[0]" to FD_INVALID */
-
 		/* Run down any open flat files to reclaim their file descriptors */
 		io_rundown(RUNDOWN_EXCEPT_STD);
 
@@ -569,9 +695,6 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 		CLOSEFILE_RESET(pipe_fds[0], pipe_status);	/* resets "pipe_fds[0]" to FD_INVALID */
 		CLOSEFILE_RESET(pipe_fds[1], pipe_status);	/* resets "pipe_fds[1]" to FD_INVALID */
 
-		/* do common cleanup in child */
-		ojchildioclean();
-
 		/* Count the number of environment variables.  */
 		for (environ_count = 0, c3 = environ, c2 = *c3;  c2;  c3++, c2 = *c3)
 			environ_count++;
@@ -617,7 +740,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 
 		string_len = STRLEN("%s=%d") + STRLEN(CHILD_FLAG_ENV) + MAX_NUM_LEN - 4;
 		if (string_len > MAX_JOB_LEN)
+		{
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
+		}
 		c1 = (char *)malloc(string_len + 1);
 #ifdef KEEP_zOS_EBCDIC
 #pragma convlit(suspend)
@@ -639,7 +765,10 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			*(pbuff + jparms->gbldir.len) = '\0';
 			string_len = STRLEN("%s=%s") + STRLEN(GBLDIR_ENV) + STRLEN(pbuff) - 4;
 			if (string_len > TEMP_BUFF_SIZE)
+			{
+				ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
+			}
 			c1 = (char *)malloc(string_len + 1);
 #ifdef KEEP_zOS_EBCDIC
 #pragma convlit(suspend)
@@ -700,9 +829,11 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			c2 = &tbuff[string_len];
 			strcpy(c2, MUMPS_EXE_STR);
 		} else
+		{
+			ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, string_len, c1,
 				SIZEOF(tbuff) - SIZEOF(MUMPS_EXE_STR));
-
+		}
 #		ifdef KEEP_zOS_EBCDIC_	/* use real strcpy to preserve env in native code set */
 #		pragma convlit(suspend)
 #		endif
@@ -720,6 +851,15 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			*(cmdbuff + jparms->cmdline.len) = 0;
 		} else
 			memset(cmdbuff, 0, TEMP_BUFF_SIZE);
+		/* Now that all job parameters (which could potentially be in relinkctl rtnobj shared memory) have been
+		 * copied over, we can get rid of our relinkctl files. Note that the below macro decrements
+		 * linkctl->hdr->nattached in the grandchild on behalf of the middle child (who did the increment).
+		 */
+		ARLINK_ONLY(RELINKCTL_RUNDOWN_MIDDLE_PARENT(need_rtnobj_shm_free, rtnhdr);)
+		/* Do common cleanup in child. Note that the below call to "ojchildioclean" invokes "relinkctl_rundown"
+		 * but that is not needed since we have already done it in the RELINKCTL_RUNDOWN_MIDDLE_PARENT invocation.
+		 */
+		ojchildioclean();
 
 #ifdef KEEP_zOS_EBCDIC
 		__getEstring1_a_copy(tbuff2, STR_AND_LEN(tbuff));
@@ -784,6 +924,5 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
 			return (EINVAL);		/* return some error condition */
 		}
 	}
-
 	return (EINVAL); /* This should never get executed, added to make compiler happy */
 }
diff --git a/sr_unix/op_fnzpeek.c b/sr_unix/op_fnzpeek.c
index 73c81db..1aae1b0 100644
--- a/sr_unix/op_fnzpeek.c
+++ b/sr_unix/op_fnzpeek.c
@@ -14,6 +14,7 @@
 #include <signal.h>
 #include "gtm_unistd.h"
 #include "gtm_string.h"
+#include "gtm_time.h"
 
 #include "send_msg.h"
 #include "error.h"
@@ -33,31 +34,39 @@
 #include "gtmrecv.h"
 #include "anticipatory_freeze.h"
 #include "gtm_caseconv.h"
+#include "jnl.h"
+#include "dollarh.h"
 
 error_def(ERR_BADZPEEKARG);
 error_def(ERR_BADZPEEKFMT);
 error_def(ERR_BADZPEEKRANGE);
 error_def(ERR_MAXSTRLEN);
+error_def(ERR_ZPEEKNOJNLINFO);
 error_def(ERR_ZPEEKNORPLINFO);
 
 #define FMTHEXDGT(spfree, digit) *spfree++ = digit + ((digit <= 9) ? '0' : ('A' - 0x0A))
 #define ARGUMENT_MAX_LEN	MAX_MIDENT_LEN
 
 /* Codes for peek operation mnemonics */
-#define PO_CSAREG	0	/* Region information - sgmnt_addrs struct - process private structure */
-#define PO_FHREG	1	/* Fileheader information from sgmnt_data for specified region */
-#define PO_GDRREG	2	/* Region information - gd_region struct - process private structure */
-#define PO_NLREG	3	/* Fileheader information from node_local for specified region (transient - non permanent) */
-#define PO_NLREPL	4	/* Fileheader information from node_local for replication dummy region */
-#define PO_GLFREPL	5	/* Replication information from gtmsrc_lcl_array structure */
-#define PO_GSLREPL	6	/* Replication information from gtmsource_local_array structure */
-#define PO_JPCREPL	7	/* Replication information from jnlpool_ctl structure */
-#define PO_PEEK		8	/* Generalized peek specifying (base) address argument */
-#define PO_RIHREPL	9	/* Replication information from repl_inst_hdr structure */
-#define PO_RPCREPL	10	/* Replication information from recvpool_ctl_struct */
-#define PO_UPLREPL	11	/* Replication information from upd_proc_local_struct */
-#define PO_GRLREPL	12	/* Replication information from gtmrecv_local_struct */
-#define PO_UHCREPL	13	/* Replication information from upd_helper_ctl */
+typedef enum
+{
+	PO_CSAREG = 0,	/* 0 Region information - sgmnt_addrs struct - process private structure */
+	PO_FHREG,	/* 1 Fileheader information from sgmnt_data for specified region */
+	PO_GDRREG,	/* 2 Region information - gd_region struct - process private structure */
+	PO_NLREG,	/* 3 Fileheader information from node_local for specified region (transient - non permanent) */
+	PO_NLREPL,	/* 4 Fileheader information from node_local for replication dummy region */
+	PO_GLFREPL,	/* 5 Replication information from gtmsrc_lcl_array structure */
+	PO_GSLREPL,	/* 6 Replication information from gtmsource_local_array structure */
+	PO_JPCREPL,	/* 7 Replication information from jnlpool_ctl structure */
+	PO_PEEK,	/* 8 Generalized peek specifying (base) address argument */
+	PO_RIHREPL,	/* 9 Replication information from repl_inst_hdr structure */
+	PO_RPCREPL,	/* 10 Replication information from recvpool_ctl_struct */
+	PO_UPLREPL,	/* 11 Replication information from upd_proc_local_struct */
+	PO_GRLREPL,	/* 12 Replication information from gtmrecv_local_struct */
+	PO_UHCREPL,	/* 13 Replication information from upd_helper_ctl */
+	PO_JNLREG,	/* 14 Journal information - jnl_private_control */
+	PO_JBFREG	/* 15 Journal buffer information - jnl_buffer_ptr_t */
+} zpeek_mnemonic;
 
 GBLREF boolean_t        created_core;
 GBLREF sigset_t		blockalrm;
@@ -94,22 +103,26 @@ LITDEF nametabent zpeek_names[] =
 	,{3, "GLF"}, {7, "GLFREPL"}	/* 6, 7 */
 	,{3, "GRL"}, {7, "GRLREPL"}	/* 8, 9 */
 	,{3, "GSL"}, {7, "GSLREPL"}	/* 10, 11 */
-	,{3, "JPC"}, {7, "JPCREPL"}	/* 12, 13 */
-	,{2, "NL"}, {5, "NLREG"}	/* 14, 15 */
-	,{6, "NLREPL"}			/* 16 */
-	,{4, "PEEK"}			/* 17 */
-	,{3, "RIH"}, {7, "RIHREPL"}	/* 18, 19 */
-	,{3, "RPC"}, {7, "RPCREPL"}	/* 20, 21 */
-	,{3, "UHC"}, {7, "UHCREPL"}	/* 22, 23 */
-	,{3, "UPL"}, {7, "UPLREPL"}	/* 24, 25 */
-	                                /* Total length 26 */
+	,{3, "JBF"}, {6, "JBFREG"}	/* 12, 13 */
+	,{3, "JPC"}, {7, "JPCREPL"}	/* 14, 15 */
+	,{3, "JNL"}, {6, "JNLREG"}	/* 16, 17 */
+	,{2, "NL"}, {5, "NLREG"}	/* 18, 19 */
+	,{6, "NLREPL"}			/* 20 */
+	,{4, "PEEK"}			/* 21 */
+	,{3, "RIH"}, {7, "RIHREPL"}	/* 22, 23 */
+	,{3, "RPC"}, {7, "RPCREPL"}	/* 24, 25 */
+	,{3, "UHC"}, {7, "UHCREPL"}	/* 26, 27 */
+	,{3, "UPL"}, {7, "UPLREPL"}	/* 28, 29 */
+	                                /* Total length 30 */
 };
+/* Index to first entry with given starting letter */
 LITDEF unsigned char zpeek_index[] =
 {
 	 0,  0,  0,  2,  2,  2,  4, 12, 12,	/* a b c d e f g h i */
-	12, 14, 14, 14, 14, 17, 17, 18, 18,	/* j k l m n o p q r */
-	22, 22, 22, 26, 26, 26, 26, 26, 26	/* s t u v w x y z ~ */
+	12, 18, 18, 18, 18, 21, 21, 22, 22,	/* j k l m n o p q r */
+	26, 26, 26, 30, 30, 30, 30, 30, 30	/* s t u v w x y z ~ */
 };
+/* Associated fetch code for each entry with flag for whether arguments accepted after code (e.g. CSAREG:MUMPS) */
 LITDEF zpeek_data_typ zpeek_data[] =
 {
 	{PO_CSAREG, 1}, {PO_CSAREG, 1}
@@ -118,7 +131,9 @@ LITDEF zpeek_data_typ zpeek_data[] =
 	,{PO_GLFREPL, 1}, {PO_GLFREPL, 1}
 	,{PO_GRLREPL, 0}, {PO_GRLREPL, 0}
 	,{PO_GSLREPL, 1}, {PO_GSLREPL, 1}
+	,{PO_JBFREG, 1}, {PO_JBFREG, 1}
 	,{PO_JPCREPL, 0}, {PO_JPCREPL, 0}
+	,{PO_JNLREG, 1}, {PO_JNLREG, 1}
 	,{PO_NLREG, 1}, {PO_NLREG, 1}
 	,{PO_NLREPL, 0}
 	,{PO_PEEK, 1}
@@ -221,6 +236,9 @@ STATICFNDEF int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtc
 	gtm_uint64_t	uint64;
 	unsigned char	*numstrstart, *numstrend;
 	unsigned char	*hexchr, *hexchrend, hexc, hexdgt, *spfree;
+	char		timebuff[MAXNUMLEN + 1];
+	time_t		seconds;
+	uint4		days;
 
 	ESTABLISH_RET(op_fnzpeek_ch, ERR_BADZPEEKRANGE);		/* If get an exception, likely due to bad range */
 	ret->mvtype = 0;						/* Prevent GC of incomplete field */
@@ -324,6 +342,18 @@ STATICFNDEF int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtc
 			ret->str.len = INTCAST(numstrend - numstrstart);
 			stringpool.free = numstrend;
 			break;
+		case 'T':						/* Time ($HOROLOG) format */
+			if ((SIZEOF(uint4) != len) && (SIZEOF(gtm_uint64_t) != len))
+				return ERR_BADZPEEKFMT;
+			ENSURE_STP_FREE_SPACE(MAXNUMLEN + 1);
+			seconds = (SIZEOF(gtm_uint64_t) == len) ? *(gtm_uint64_t *)zpeekadr : *(uint4 *)zpeekadr;
+			dollarh(seconds, &days, &seconds);
+			ret->str.addr = (char *)stringpool.free;
+			stringpool.free  = i2asc(stringpool.free, days);
+			*stringpool.free++ = ',';
+			stringpool.free = i2asc(stringpool.free, (uint4)seconds);
+			ret->str.len = INTCAST((char *)stringpool.free - ret->str.addr);
+			break;
 		case 'Z':						/* Hex format (no 0x prefix) of storage as it exists */
 			if ((len * 2) > MAX_STRLEN)
 			{	/* Requested string return is too large */
@@ -412,6 +442,7 @@ void	op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
 	replpool_identifier	replpool_id;
 	unsigned int		full_len;
 	unsigned char		argument_uc_buf[ARGUMENT_MAX_LEN];
+	sgmnt_addrs		*csa;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -452,6 +483,8 @@ void	op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
 			case PO_FHREG:
 			case PO_GDRREG:
 			case PO_NLREG:
+			case PO_JNLREG:
+			case PO_JBFREG:
 				/* Uppercase the region name since that is what GDE does when creating them */
 				lower_to_upper(argument_uc_buf, argptr, arglen);
 				argptr = argument_uc_buf;	/* Reset now to point to upper case version */
@@ -522,6 +555,13 @@ void	op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
 		case PO_NLREG:		/* r_ptr set from option processing */
 			zpeekadr = (&FILE_INFO(r_ptr)->s_addrs)->nl;
 			break;
+		case PO_JNLREG:		/* r_ptr set from option processing */
+		case PO_JBFREG:
+			csa = &FILE_INFO(r_ptr)->s_addrs;
+			if ((NULL == csa->jnl) || (jnl_open != csa->hdr->jnl_state))
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZPEEKNOJNLINFO, 2, REG_LEN_STR(r_ptr));
+			zpeekadr = (PO_JNLREG == mnemonic_opcode) ? (void *)csa->jnl : (void *)csa->jnl->jnl_buff;
+			break;
 		case PO_GLFREPL:	/* This set of opcodes all require the journal pool to be initialized. Verify it */
 		case PO_GSLREPL:
 		case PO_JPCREPL:
@@ -612,6 +652,7 @@ void	op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
 			case 'C':	/* Character data - returned as is */
 			case 'I':	/* Signed integer format - up to 31 bits */
 			case 'S':	/* String data - Same as 'C' except string is NULL terminated */
+			case 'T':	/* Time ($H) format - length must be of 4 or 8 byte unsigned int */
 			case 'U':	/* Unsigned integer format - up to 64 bits */
 			case 'X':	/* Humeric hex format: e.g. 0x12AB. Total length is (2 * bytes) + 2 */
 			case 'Z':	/* Hex format - not treated as numeric. Shown as occurs in memory (subject to endian)
diff --git a/sr_unix/op_fnzsearch.c b/sr_unix/op_fnzsearch.c
index 6f2332f..a268e2b 100644
--- a/sr_unix/op_fnzsearch.c
+++ b/sr_unix/op_fnzsearch.c
@@ -72,7 +72,7 @@ int op_fnzsearch(mval *file, mint indx, mint mfunc, mval *ret)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	if (mfunc && ((MAX_STRM_CT < indx) || ( 0 > indx)))	/* Allow out-of-range stream if internal call */
+	if (mfunc && ((MAX_STRM_CT <= indx) || ( 0 > indx)))	/* Allow out-of-range stream if internal call */
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZSRCHSTRMCT);
 	ESTABLISH_RET(fnzsrch_ch, -1);
 	TREF(fnzsearch_nullsubs_sav) = TREF(lv_null_subs);
diff --git a/sr_unix/op_lab_ext.c b/sr_unix/op_lab_ext.c
index 6fa4396..01bc85b 100644
--- a/sr_unix/op_lab_ext.c
+++ b/sr_unix/op_lab_ext.c
@@ -13,7 +13,7 @@
 
 #include <rtnhdr.h>
 
-#ifdef USHBIN_SUPPORTED /* entire file */
+#ifdef AUTORELINK_SUPPORTED /* entire file */
 /* Routine to provide the content of the thread-local variable "lab_lnr" as a return value to
  * generated code.
  *
@@ -29,4 +29,4 @@ void *op_lab_ext(void)
 	SETUP_THREADGBL_ACCESS;
 	return TREF(lab_lnr);
 }
-#endif /* USHBIN_SUPPORTED over entire file */
+#endif /* AUTORELINK_SUPPORTED over entire file */
diff --git a/sr_unix/op_rhd_ext.c b/sr_unix/op_rhd_ext.c
index 13673ae..aa469aa 100644
--- a/sr_unix/op_rhd_ext.c
+++ b/sr_unix/op_rhd_ext.c
@@ -11,14 +11,16 @@
 
 #include "mdef.h"
 
-#ifdef USHBIN_SUPPORTED /* entire file */
+#ifdef AUTORELINK_SUPPORTED /* entire file */
 #include "gtm_string.h"
 
 #include <rtnhdr.h>
 #include "op.h"
 #include "relinkctl.h"
-#include "zhist.h"
 #include "min_max.h"
+#include "zbreak.h"
+
+GBLREF z_records 	zbrk_recs;	/* ZBREAKs in effect */
 
 /* Rebuffering macro for routine and label name for use when needed. Note we don't even do the
  * MV_FORCE_STR() on the given mval until we know we are going to use it.
@@ -52,12 +54,9 @@ rhdtyp *op_rhd_ext(mval *rtname, mval *lbname, rhdtyp *rhd, void *lnr)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	/* The are two potential future updates here:
-	 *   1. Desire to remove the two additional opcodes and revert back to the single call opcode (op_call, op_extexfun, etc).
-	 *      This would have positive performance enhancements through less generated code and shorter call path if doable.
-	 *   2. Intention is to change the syntax of ZRUPDATE such that routines can be specified in groups surrounded by
-	 *	parentheses (e.g. ZRUPDATE (a.o,b.o,c.o)) which would make all 3 routines available simultaneously instead of
-	 *	serially. This will likely require some sort of locking protocols but is not yet defined.
+	/* Future TODO:
+	 *   Remove the two additional opcodes and revert back to the single call opcode (op_call, op_extexfun, etc).
+	 *   This would have positive performance enhancements through less generated code and shorter call path if doable.
 	 */
 	if (NULL == rhd)
 	{	/* Routine is not yet linked - perform auto-ZLINK */
@@ -70,23 +69,27 @@ rhdtyp *op_rhd_ext(mval *rtname, mval *lbname, rhdtyp *rhd, void *lnr)
 		return rhd;
 	}
 	/* Routine is already linked, but we need to check if a new version is available. This involves traversing the
-	 * "validation linked list", looking for changes in different $zro entries. But we also need to base our checks
-	 * on the most recent version of the routine loaded.
+	 * "validation linked list", looking for changes in different $ZROUTINES entries. But we also need to base our
+	 * checks on the most recent version of the routine loaded. Note autorelink is only possible when no ZBREAKs are
+	 * defined in the given routine.
 	 */
-	rhd = rhd->current_rhead_adr;
-	if ((NULL != rhd->zhist) && need_relink(rhd, (zro_hist *)rhd->zhist))
-	{
-		REBUFFER_MIDENT(rtname, &rtnname, rtnname_buff);
-		REBUFFER_MIDENT(lbname, &lblname, lblname_buff);
-		op_zlink(&rtnname, NULL);
-		rhd = rhd->current_rhead_adr;		/* Pickup routine header of new version to avoid lookup */
-		assert((NULL == rhd->zhist) || (((zro_hist *)(rhd->zhist))->zroutines_cycle == TREF(set_zroutines_cycle)));
-		op_labaddr(rhd, &lblname, 0);
-		TREF(lab_lnr) = &((TREF(lab_proxy)).lnr_adr);
-		return rhd;
+	if (!rhd->has_ZBREAK)
+	{	/* Only look for autorelink when no ZBREAKs are defined in this routine */
+		rhd = rhd->current_rhead_adr;		/* Update rhd to most currently linked version */
+		if ((NULL != rhd->zhist) && need_relink(rhd, (zro_hist *)rhd->zhist))
+		{	/* Relink appears to be needed */
+			REBUFFER_MIDENT(rtname, &rtnname, rtnname_buff);
+			REBUFFER_MIDENT(lbname, &lblname, lblname_buff);
+			op_zlink(&rtnname, NULL);
+			rhd = rhd->current_rhead_adr;		/* Pickup routine header of new version to avoid lookup */
+			assert((NULL == rhd->zhist) || (((zro_hist *)(rhd->zhist))->zroutines_cycle == TREF(set_zroutines_cycle)));
+			op_labaddr(rhd, &lblname, 0);
+			TREF(lab_lnr) = &((TREF(lab_proxy)).lnr_adr);
+			return rhd;
+		}
 	}
 	/* Linked routine is already the latest */
 	TREF(lab_lnr) = lnr;
 	return rhd;
 }
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/op_zedit.c b/sr_unix/op_zedit.c
index c995e3f..5dcdca5 100644
--- a/sr_unix/op_zedit.c
+++ b/sr_unix/op_zedit.c
@@ -26,13 +26,15 @@
 #include "setterm.h"
 #include "op.h"
 #include "fork_init.h"
+#include "geteditor.h"
+#include "wbox_test_init.h"
 
 GBLREF	io_pair		io_std_device;
 GBLREF	mval 		dollar_zsource;
 GBLREF	mstr		editor;
 GBLREF	int4		dollar_zeditor;
 
-error_def(ERR_FILENOTFND);
+error_def(ERR_NOEDITOR);
 error_def(ERR_ZEDFILSPEC);
 
 void op_zedit(mval *v, mval *p)
@@ -43,9 +45,9 @@ void op_zedit(mval *v, mval *p)
 	int		objcnt;
 	int		waitid;
 	unsigned int	childid, status;
-#ifdef _BSD
+#	ifdef _BSD
 	union wait	wait_status;
-#endif
+#	endif
 	bool		has_ext, exp_dir;
 	parse_blk	pblk;
 	mstr		src;
@@ -54,12 +56,13 @@ void op_zedit(mval *v, mval *p)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	geteditor();
 	if (!editor.len)
 	{
 		edt = GETENV("EDITOR");
 		if (!edt)
 			edt = "editor";
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt));
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOEDITOR, 2, LEN_AND_STR(edt));
 	}
 	MV_FORCE_STR(v);
 	MV_FORCE_STR(p);
@@ -117,7 +120,7 @@ void op_zedit(mval *v, mval *p)
 		src.addr = es;
 		src.len = path_len;
 		srcdir = (zro_ent *)0;
-		zro_search(0, 0, &src, &srcdir, TRUE);
+		zro_search(NULL, NULL, &src, &srcdir, TRUE);
 		if (NULL == srcdir)
 		{	/* find the first source directory */
 			objcnt = (TREF(zro_root))->count;
@@ -184,7 +187,9 @@ void op_zedit(mval *v, mval *p)
 			setterm(io_std_device.in);
 	} else
 	{
+		if (WBTEST_ENABLED(WBTEST_BADEXEC_OP_ZEDIT))
+			STRCPY(editor.addr, "");
 		EXECL(editor.addr, editor.addr, es, 0);
-		exit(-1);
+		_exit(-1);
 	}
 }
diff --git a/sr_unix/op_zlink.c b/sr_unix/op_zlink.c
index ebc5c32..efd31d3 100644
--- a/sr_unix/op_zlink.c
+++ b/sr_unix/op_zlink.c
@@ -18,6 +18,9 @@
 #include <errno.h>
 
 #include "stringpool.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h"
+#endif
 #include "zroutines.h"
 #include "cmd_qlf.h"
 #include "parse_file.h"
@@ -27,12 +30,15 @@
 #include "incr_link.h"
 #include "compiler.h"
 #ifdef __MVS__
-#include "gtm_zos_io.h"
+# include "gtm_zos_io.h"
 #endif
 
-#define SRC			1
-#define OBJ			2
-#define NOTYPE			3
+typedef enum
+{
+	SRC = 1,
+	OBJ,
+	NOTYPE
+} linktyp;
 
 /* On shared platforms, skip parameter should be FALSE to indicate an auto-ZLINK so that
  * zro_search looks into shared libraries. On non-shared platforms, it should be
@@ -58,21 +64,47 @@
 #elif defined(__hpux) && defined(__ia64)
 #  define st_nmtime		st_nmtime
 #endif
+/* Macro to close object file and give appropriate error */
+#define CLOSE_OBJECT_FD(FD, STATUS)												\
+{																\
+	CLOSE_OBJECT_FILE(FD, STATUS);	/* Resets "object_file_des" to FD_INVALID */						\
+	if (-1 == status)													\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno);	\
+}
 
-#define CLOSE_OBJECT_FD(FD, STATUS)	CLOSEFILE_RESET(FD, STATUS)       /* resets "object_file_des" to FD_INVALID */
+#ifdef AUTORELINK_SUPPORTED
+#  define CHECK_OBJECT_HISTORY(OBJPATH, OBJDIR, RECENT_ZHIST_PARM)								\
+{																\
+	if (TREF(arlink_enabled) && !TREF(trigger_compile))									\
+	{	/* Autorelink is enabled, this is not a trigger and we need a search history for the object file to pass	\
+		 * to incr_link(). We had to wait till this point to discover the search history since at the time of the	\
+		 * call to zro_search(), there may not have been an object file to find or, given where we found the source,	\
+		 * the object file we are linking now may be different from one found before so create the history array given  \
+		 * the supplied object file path and our $ZROUTINES directory array.						\
+		 *														\
+		 * Note we cannot assert RECENT_ZHIST_PARM is null here as we may be about to link a recompiled module after	\
+		 * a failed ZLINK but incr_link() took care of releasing the old history in its error path.			\
+		 */														\
+		RECENT_ZHIST_PARM = zro_search_hist(OBJPATH, &OBJDIR);								\
+	}															\
+}
+#else
+#  define CHECK_OBJECT_HISTORY(OBJPATH, OBJDIR, RECENT_ZHIST_PARM)
+#endif
 
 GBLREF spdesc			stringpool;
 GBLREF command_qualifier	glb_cmd_qlf, cmd_qlf;
 GBLREF mval			dollar_zsource;
 GBLREF int			object_file_des;
 
-error_def(ERR_WILDCARD);
-error_def(ERR_VERSION);
 error_def(ERR_FILENOTFND);
-error_def(ERR_ZLINKFILE);
-error_def(ERR_ZLNOOBJECT);
 error_def(ERR_FILEPARSE);
+error_def(ERR_SYSCALL);
 error_def(ERR_TEXT);
+error_def(ERR_VERSION);
+error_def(ERR_WILDCARD);
+error_def(ERR_ZLINKFILE);
+error_def(ERR_ZLNOOBJECT);
 ZOS_ONLY(error_def(ERR_BADTAG);)
 
 /* Routine to locate object files, or source and compile to an object file if necessary, and drive the linker to link the file
@@ -91,8 +123,8 @@ ZOS_ONLY(error_def(ERR_BADTAG);)
  */
 void op_zlink (mval *v, mval *quals)
 {
-	int			status, qlf, tslash;
-	unsigned short		type;
+	int			status, qlf, tslash, save_errno;
+	linktyp			type;
 	char			srcnamebuf[MAX_FBUFF + 1], objnamebuf[MAX_FBUFF + 1], *fname;
 	uint4			objnamelen, srcnamelen;
 	char			inputf[MAX_FBUFF + 1], obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1],
@@ -103,17 +135,23 @@ void op_zlink (mval *v, mval *quals)
 	parse_blk		pblk;
 	mval			qualifier;
 	struct stat		obj_stat, src_stat;
+	ARLINK_ONLY(zro_hist	*recent_zhist;)
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	ARLINK_ONLY(recent_zhist = NULL);
 	MV_FORCE_STR(v);
-	if (!v->str.len || (MAX_FBUFF < v->str.len))
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
+	if (!v->str.len)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr, ERR_TEXT, 2,
+			      RTS_ERROR_LITERAL("Filename/path is missing"));
+	if (MAX_FBUFF < v->str.len)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr, ERR_TEXT, 2,
+			      RTS_ERROR_LITERAL("Filename/path exceeds max length"));
 	object_file_des = FD_INVALID;
 	srcdir = objdir = NULL;
 	expdir = FALSE;
 	if (quals)
-	{	/* Explicit ZLINK */
+	{	/* Explicit ZLINK from generated code or from gtm_trigger() */
 		memset(&pblk, 0, SIZEOF(pblk));
 		pblk.buff_size = MAX_FBUFF;
 		pblk.buffer = inputf;
@@ -147,13 +185,13 @@ void op_zlink (mval *v, mval *quals)
 		dollar_zsource.str.len = file.len;
 		stringpool.free += file.len;
 		if (OBJ == type)
-		{
-			memmove(objnamebuf,file.addr, file.len + pblk.b_ext);
+		{	/* Object file extension specified */
+			memmove(objnamebuf, file.addr, file.len + pblk.b_ext);
 			objnamelen = file.len + pblk.b_ext;
 			assert (objnamelen <= MAX_FBUFF + 1);
 			objnamebuf[objnamelen] = 0;
 		} else if (SRC == type)
-		{
+		{	/* Non-object file extension specified */
 			memmove(srcnamebuf, file.addr,file.len + pblk.b_ext);
 			srcnamelen = file.len + pblk.b_ext;
 			assert (srcnamelen <= MAX_FBUFF + 1);
@@ -162,11 +200,11 @@ void op_zlink (mval *v, mval *quals)
 			if (pblk.b_name > MAX_MIDENT_LEN)
 				objnamelen = expdir ? (pblk.b_dir + MAX_MIDENT_LEN) : MAX_MIDENT_LEN;
 			memcpy(objnamebuf, file.addr, objnamelen);
-			memcpy(&objnamebuf[objnamelen], DOTOBJ, SIZEOF(DOTOBJ));
+			memcpy(&objnamebuf[objnamelen], DOTOBJ, SIZEOF(DOTOBJ));	/* Copies null terminator */
 			objnamelen += STR_LIT_LEN(DOTOBJ);
 			assert (objnamelen + SIZEOF(DOTOBJ) <= MAX_FBUFF + 1);
 		} else
-		{
+		{	/* No file extension specified */
 			if ((file.len + SIZEOF(DOTM) > SIZEOF(srcnamebuf)) ||
 			    (file.len + SIZEOF(DOTOBJ) > SIZEOF(objnamebuf)))
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
@@ -175,40 +213,40 @@ void op_zlink (mval *v, mval *quals)
 			srcnamelen = file.len + SIZEOF(DOTM) - 1;
 			assert (srcnamelen + SIZEOF(DOTM) <= MAX_FBUFF + 1);
 			memcpy(objnamebuf,file.addr,file.len);
-			memcpy(&objnamebuf[file.len], DOTOBJ, SIZEOF(DOTOBJ));
+			memcpy(&objnamebuf[file.len], DOTOBJ, SIZEOF(DOTOBJ));		/* Copies null terminator */
 			objnamelen = file.len + SIZEOF(DOTOBJ) - 1;
 			assert (objnamelen + SIZEOF(DOTOBJ) <= MAX_FBUFF + 1);
 		}
 		if (!expdir)
-		{
+		{	/* No full or relative directory specified on file to link - fill it in */
 			srcstr.addr = srcnamebuf;
 			srcstr.len = srcnamelen;
 			objstr.addr = objnamebuf;
 			objstr.len = objnamelen;
 			if (OBJ == type)
-			{
+			{	/* Explicit ZLINK of object - don't locate source */
 				zro_search(&objstr, &objdir, NULL, NULL, SKIP_SHLIBS);
-				if (!objdir)
+				if (NULL == objdir)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len,
-						dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
-						dollar_zsource.str.addr);
+						      dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
+						      dollar_zsource.str.addr);
 			} else if (SRC == type)
-			{
+			{	/* Explicit ZLINK of source - locate both source and object*/
 				zro_search(&objstr, &objdir, &srcstr, &srcdir, SKIP_SHLIBS);
-				if (!srcdir)
+				if (NULL == srcdir)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf,
-						ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
+						      ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
 			} else
-			{
+			{	/* Explicit ZLINK no file type specified - locate both source and object */
 				zro_search(&objstr, &objdir, &srcstr, &srcdir, PROBE_SHLIBS);
-				if (!objdir && !srcdir)
+				if ((NULL == objdir) && (NULL == srcdir))
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len,
-						dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
-						dollar_zsource.str.addr);
+						      dollar_zsource.str.addr, ERR_FILENOTFND,2, dollar_zsource.str.len,
+						      dollar_zsource.str.addr);
 			}
 		}
 	} else
-	{	/* auto-ZLINK */
+	{	/* auto-ZLINK for execution, ZBREAK, $TEXT(), or ZEDIT (i.e. non-specific call to op_zlink()) */
 		type = NOTYPE;
 		memcpy(srcnamebuf, v->str.addr, v->str.len);
 		memcpy(&srcnamebuf[v->str.len], DOTM, SIZEOF(DOTM));
@@ -216,56 +254,54 @@ void op_zlink (mval *v, mval *quals)
 		if ('%' == srcnamebuf[0])
 			srcnamebuf[0] = '_';
 		memcpy(objnamebuf, srcnamebuf, v->str.len);
-		memcpy(&objnamebuf[v->str.len], DOTOBJ, SIZEOF(DOTOBJ));
+		memcpy(&objnamebuf[v->str.len], DOTOBJ, SIZEOF(DOTOBJ));		/* Copies null terminator */
 		objnamelen = v->str.len + SIZEOF(DOTOBJ) - 1;
 		srcstr.addr = srcnamebuf;
 		srcstr.len = srcnamelen;
 		objstr.addr = objnamebuf;
 		objstr.len = objnamelen;
 		zro_search(&objstr, &objdir, &srcstr, &srcdir, PROBE_SHLIBS);
-		if (!objdir && !srcdir)
+		if ((NULL == objdir) && (NULL == srcdir))
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
-				ERR_FILENOTFND, 2, v->str.len, v->str.addr);
+				      ERR_FILENOTFND, 2, v->str.len, v->str.addr);
 		qualifier.mvtype = MV_STR;
 		qualifier.str = TREF(dollar_zcompile);
 		quals = &qualifier;
 	}
 	if (OBJ == type)
-	{
+	{	/* Object file extension specified */
 		if (objdir)
-		{
+		{	/* Object file found via zro_search() */
 			assert(ZRO_TYPE_OBJLIB != objdir->type);
 			if (objdir->str.len + objnamelen + 2 > SIZEOF(objnamebuf))
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
 			if (objdir->str.len)
 			{
 				tslash = ('/' == objdir->str.addr[objdir->str.len - 1]) ? 0 : 1;
-				memmove(&objnamebuf[ objdir->str.len + tslash], objnamebuf, objnamelen);
+				memmove(&objnamebuf[objdir->str.len + tslash], objnamebuf, objnamelen);
 				if (tslash)
-					objnamebuf[ objdir->str.len ] = '/';
+					objnamebuf[objdir->str.len] = '/';
 				memcpy(objnamebuf, objdir->str.addr, objdir->str.len);
 				objnamelen += objdir->str.len + tslash;
-				objnamebuf[ objnamelen ] = 0;
+				objnamebuf[objnamelen] = 0;
 			}
 		}
 		OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
 		if (FD_INVALID == object_file_des)
+			/* Could not find object file */
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
-			errno);
-		if (IL_RECOMPILE == incr_link(object_file_des, NULL, objnamelen, objnamebuf))
+				      errno);
+		/* Note - if explicit ZLINK, objdir can be NULL if link is from a directory not mentioned in $ZROUTINES */
+		CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
+		if (IL_RECOMPILE == INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf))
 		{
-			CLOSE_OBJECT_FD(object_file_des, status);	/* No checking for error here as the priority error
-									 * right now is the version issue.
-									 */
+			CLOSE_OBJECT_FILE(object_file_des, status);	/* Priority error is version issue so ignore any on close */
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
-				ERR_VERSION);
+				      ERR_VERSION);
 		}
 		CLOSE_OBJECT_FD(object_file_des, status);
-		if (-1 == status)
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
-			errno);
 	} else
-	{	/* either NO type or SOURCE type */
+	{	/* Either NO file extension specified or is SOURCE file extension type */
 		cmd_qlf.object_file.str.addr = obj_file;
 		cmd_qlf.object_file.str.len = MAX_FBUFF;
 		cmd_qlf.list_file.str.addr = list_file;
@@ -273,31 +309,33 @@ void op_zlink (mval *v, mval *quals)
 		cmd_qlf.ceprep_file.str.addr = ceprep_file;
 		cmd_qlf.ceprep_file.str.len = MAX_FBUFF;
 		if (srcdir)
-		{
+		{	/* A source directory containing routine was found by zro_search() */
 			assert(ZRO_TYPE_OBJLIB != objdir->type);
 			if (srcdir->str.len + srcnamelen > SIZEOF(srcnamebuf) - 1)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZLINKFILE, 2, v->str.len, v->str.addr);
 			if (srcdir->str.len)
 			{
 				tslash = ('/' == srcdir->str.addr[srcdir->str.len - 1]) ? 0 : 1;
-				memmove(&srcnamebuf[ srcdir->str.len + tslash ], srcnamebuf, srcnamelen);
+				memmove(&srcnamebuf[srcdir->str.len + tslash], srcnamebuf, srcnamelen);
 				if (tslash)
-					srcnamebuf[ srcdir->str.len ] = '/';
+					srcnamebuf[srcdir->str.len] = '/';
 				memcpy(srcnamebuf, srcdir->str.addr, srcdir->str.len);
 				srcnamelen += srcdir->str.len + tslash;
-				srcnamebuf[ srcnamelen ] = 0;
+				srcnamebuf[srcnamelen] = 0;
 			}
 		}
 		if (objdir)
-		{
+		{	/* An object directory or shared library containing the routine was found by zro_search() */
 			if (ZRO_TYPE_OBJLIB == objdir->type)
-			{
+			{	/* For object libraries, there are no auto-relink complications so no need to hunt down
+				 * any history for it or to pass in any.
+				 */
 				assert(objdir->shrlib);
 				assert(objdir->shrsym);
 				/* The incr_link() routine should drive errors for any issue found with linking from a shared
 				 * library so IL_DONE is the only valid return code we *ever* expect back.
 				 */
-				assertpro(IL_DONE == incr_link(0, objdir, objnamelen, objnamebuf));
+				assertpro(IL_DONE == INCR_LINK(0, objdir, NULL, objnamelen, objnamebuf));
 				return;
 			}
 			if (objdir->str.len + objnamelen > SIZEOF(objnamebuf) - 1)
@@ -305,17 +343,20 @@ void op_zlink (mval *v, mval *quals)
 			if (objdir->str.len)
 			{
 				tslash = ('/' == objdir->str.addr[objdir->str.len - 1]) ? 0 : 1;
-				memmove(&objnamebuf[ objdir->str.len + tslash ], objnamebuf, objnamelen);
+				memmove(&objnamebuf[objdir->str.len + tslash], objnamebuf, objnamelen);
 				if (tslash)
-					objnamebuf[ objdir->str.len ] = '/';
+					objnamebuf[objdir->str.len] = '/';
 				memcpy(objnamebuf, objdir->str.addr, objdir->str.len);
 				objnamelen += objdir->str.len + tslash;
-				objnamebuf[ objnamelen ] = 0;
+				objnamebuf[objnamelen] = 0;
 			}
 		}
+		/* Check which source/object we ended up with and whether they are for the same file or not so we can determine if
+		 * recompilation might be required.
+		 */
 		src_found = obj_found = compile = FALSE;
 		if (SRC != type)
-		{
+		{	/* Object or NO file extension specified - check object file exists */
 			OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
 			if (FD_INVALID == object_file_des)
 			{
@@ -325,68 +366,82 @@ void op_zlink (mval *v, mval *quals)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
 			} else
 				obj_found = TRUE;
-		} else
+		} else	/* If source file extension specified, force re-compile */
 			compile = TRUE;
-		STAT_FILE(srcnamebuf, &src_stat, status);
+		STAT_FILE(srcnamebuf, &src_stat, status);	/* Check if source file exists */
 		if (-1 == status)
 		{
 			if ((ENOENT == errno) && (SRC != type))
 				src_found = FALSE;
 			else
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE,2,srcnamelen,srcnamebuf,errno);
+			{
+				save_errno = errno;
+				if (FD_INVALID != object_file_des)	/* Chose object file if open, ignore error */
+					CLOSE_OBJECT_FILE(object_file_des, status);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, save_errno);
+			}
 		} else
 			src_found = TRUE;
 		if (SRC != type)
-		{
+		{	/* If object or no file extension type specified, check if have both source and object and if so, decide
+			 * if source needs to be recompiled.
+			 */
 			if (src_found)
 			{
 				if (obj_found)
 				{
 					FSTAT_FILE(object_file_des, &obj_stat, status);
 					if (-1 == status)
+					{
+						save_errno = errno;
+						if (FD_INVALID != object_file_des)	/* Close object file if open */
+							CLOSE_OBJECT_FILE(object_file_des, status);
 						rts_error_csa(CSA_ARG(NULL)VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
-							      errno);
+							      save_errno);
+					}
 					if ((src_stat.st_mtime > obj_stat.st_mtime)
-						|| ((src_stat.st_mtime == obj_stat.st_mtime)
-							&& (src_stat.st_nmtime > obj_stat.st_nmtime)))
+					    || ((src_stat.st_mtime == obj_stat.st_mtime)
+						&& (src_stat.st_nmtime > obj_stat.st_nmtime)))
 					{
 						CLOSE_OBJECT_FD(object_file_des, status);
-						if (-1 == status)
-							rts_error_csa(CSA_ARG(NULL)VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen,
-								      objnamebuf, errno);
 						compile = TRUE;
 					}
 				} else
+				{
 					compile = TRUE;
+					assert(FD_INVALID == object_file_des);	/* Make sure closed */
+				}
 			} else if (!obj_found)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
-					ERR_FILENOTFND, 2, objnamelen, objnamebuf);
+					      ERR_FILENOTFND, 2, objnamelen, objnamebuf);
 		}
 		if (compile)
-		{
+		{	/* (Re)Compile source file */
 			zl_cmd_qlf(&quals->str, &cmd_qlf);
 			if (!MV_DEFINED(&cmd_qlf.object_file))
-			{
+			{	/* -object= parameter NOT specified - fill in default */
 				cmd_qlf.object_file.mvtype = MV_STR;
 				cmd_qlf.object_file.str.addr = objnamebuf;
 				cmd_qlf.object_file.str.len = objnamelen;
 			}
 			qlf = cmd_qlf.qlf;
-			if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
+			if (!(qlf & CQ_OBJECT) && (SRC != type))
 			{
 				cmd_qlf.qlf = glb_cmd_qlf.qlf;
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
 			}
 			zlcompile(srcnamelen, (uchar_ptr_t)srcnamebuf);
+			assert(FD_INVALID == object_file_des);	/* zlcompile() should have driven obj_code() which closes object */
 			if ((SRC == type) && !(qlf & CQ_OBJECT))
 				return;
+			OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
 		}
-		status = incr_link(object_file_des, objdir, objnamelen, objnamebuf);
+		assert(FD_INVALID != object_file_des);		/* Object file should be open at this point */
+		CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
+		status = INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf);
 		if (IL_RECOMPILE == status)
-		{	/* due only to version mismatch, so recompile */
+		{	/* Failure due only to version mismatch, so recompile */
 			CLOSE_OBJECT_FD(object_file_des, status);
-			if (-1 == status)
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
 			assertpro(!compile);
 			if (!src_found)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_VERSION);
@@ -403,15 +458,16 @@ void op_zlink (mval *v, mval *quals)
 				cmd_qlf.qlf = glb_cmd_qlf.qlf;
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
 			}
+			assert(FD_INVALID == object_file_des);	/* zlcompile() should have driven obj_code() which closes it */
+			OPEN_OBJECT_FILE(objnamebuf, O_RDONLY, object_file_des);
+			CHECK_OBJECT_HISTORY(objnamebuf, objdir, RECENT_ZHIST);
 			/* We just did a fresh re-compile a few lines above so IL_DONE is the only return code we ever
 			 * expect to see back. Only a race-condition created by a different version overlaying the newly
 			 * created object file could conceivably cause an IL_RECOMPILE code here (incr_link handles all
 			 * the other errors itself). Not at this time considered worthy of special coding.
 			 */
-			assertpro(IL_DONE == incr_link(object_file_des, objdir, objnamelen, objnamebuf));
+			assertpro(IL_DONE == INCR_LINK(object_file_des, objdir, RECENT_ZHIST, objnamelen, objnamebuf));
 		}
 		CLOSE_OBJECT_FD(object_file_des, status);
-		if (-1 == status)
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, errno);
 	}
 }
diff --git a/sr_unix/op_zrupdate.c b/sr_unix/op_zrupdate.c
index e478dac..939e691 100644
--- a/sr_unix/op_zrupdate.c
+++ b/sr_unix/op_zrupdate.c
@@ -19,39 +19,59 @@
 #include "gtm_stat.h"
 #include "gtm_stdlib.h"
 
+#include "gtmio.h"
 #include "io.h"
 #include "iosp.h"
 #include <rtnhdr.h>
 #include "relinkctl.h"
-#include "zhist.h"
 #include "parse_file.h"
 #include "eintr_wrappers.h"
 #include "error.h"
 #include "min_max.h"
 #include "op.h"
 #include "op_fnzsearch.h"
+#include "interlock.h"
+#include "toktyp.h"
+#include "valid_mname.h"
+#ifdef DEBUG
+# include "toktyp.h"		/* Needed for "valid_mname.h" */
+#endif
 
+#define DOTOBJEXT	".o"
 #define OBJEXT 		'o'
 #define WILDCARD	'*'
 
+LITREF	mval	literal_null;
 
-#ifndef USHBIN_SUPPORTED
+error_def(ERR_FILEPARSE);
+error_def(ERR_PARNORMAL);
+error_def(ERR_TEXT);
+
+#ifndef AUTORELINK_SUPPORTED
 /* Stub routine for unsupported platforms */
 void op_zrupdate(int argcnt, ...)
 {
 	return;
 }
 #else
-/************************************************************/
-
-LITREF	mval	literal_null;
-
-error_def(ERR_FILEPARSE);
-error_def(ERR_PARNORMAL);
-error_def(ERR_TEXT);
-
-/*
- * TODO: Add description of syntax/operation
+/* The ZRUPDATE command drives this routine once through for each argument (object file path and object file - potentially
+ * containing wildcards). Each file specified, or found in a wildcard search, is separated into its path and its routine
+ * name, the path is looked up and the appropriate relinkctl file opened where we lookup the routine name and bump its cycle.
+ *
+ * Although this routine is setup to handle a variable argument list, more than 1 argument is not currently supported. The
+ * ZRUPDATE command itself does support a commented list of filespecs but the compiler turns each argument into a separate
+ * call to this routine. The purpose of the variable argument list is to support a future proposed enhancement which would
+ * allow a ZRUPDATE argument to be a parenthesized list of filespecs with the intention all of them are simultaneously
+ * updated. Such a list, when supported would be passed as a list of files to this routine - hence the multi-arg support.
+ *
+ * To get a consistent view of each directory, the directory is run through realpath() to resolve soft links and normalize the
+ * directory name consistently.
+ *
+ * Parameters:
+ *   argcnt        - currently always 1 (see note above).
+ *   objfilespec   - mval address holding string containing filespec to process.
+ *
+ * No return value.
  */
 
 void op_zrupdate(int argcnt, ...)
@@ -59,16 +79,17 @@ void op_zrupdate(int argcnt, ...)
 	mval			*objfilespec;
 	va_list			var;
 	mval			objpath;
-	char			tranbuf[MAX_FBUFF + 1], *chptr;
+	char			tranbuf[MAX_FBUFF + 1], *chptr, chr;
 	open_relinkctl_sgm 	*linkctl;
-	relinkrec_loc_t		rec;
+	relinkrec_t		*rec;
 	plength			plen;
-	int			status, fextlen;
+	int			status, fextlen, fnamlen, fcnt;
 	parse_blk		pblk;
 	struct stat		outbuf;
         int			stat_res;
-	boolean_t		seenfext, seenwildcard;
+	boolean_t		seenfext, fileexists;
 	mstr			objdir, rtnname;
+	uint4			hash, prev_hash_index;
 
 	/* Currently only expecting one value per invocation right now. That will change in phase 2 hence the stdarg setup */
 	va_start(var, argcnt);
@@ -76,50 +97,103 @@ void op_zrupdate(int argcnt, ...)
 	objfilespec = va_arg(var, mval *);
 	va_end(var);
 	MV_FORCE_STR(objfilespec);
-	/* First some pre-processing to determine if an explicit file type was specified. If so, it must be ".o" for this
-	 * phase of implementation. Later phases may allow ".m" to be specified but not initially. Use parse_file() to
+	/* First some pre-processing to determine if an explicit file name or type was specified. If so, it must be ".o" for
+	 * this phase of implementation. Later phases may allow ".m" to be specified but not initially. Use parse_file() to
 	 * parse everything out and isolate any extention.
 	 */
 	memset(&pblk, 0, SIZEOF(pblk));
         pblk.buffer = tranbuf;
-	pblk.buff_size = (unsigned char)(MAX_FBUFF);
-	pblk.fnb = 0;
+	pblk.buff_size = (unsigned char)(MAX_FBUFF);	/* Pass size of buffer - 1 (standard protocol for parse_file) */
+	pblk.def1_buf = DOTOBJEXT;			/* Default .o file type if not specified */
+	pblk.def1_size = SIZEOF(DOTOBJEXT) - 1;
+	pblk.fop = F_SYNTAXO;				/* Syntax check only - bypass directory existence check */
 	status = parse_file(&objfilespec->str, &pblk);
 	if (ERR_PARNORMAL != status)
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len, objfilespec->str.addr, status);
+	tranbuf[pblk.b_esl] = '\0';			/* Needed for subsequent STAT_FILE */
+	seenfext = FALSE;
 	if (0 != pblk.b_ext)
 	{	/* If a file extension was specified - get the extension sans any potential wildcard character */
-		seenfext = seenwildcard = FALSE;
 		for (chptr = pblk.l_ext + 1, fextlen = pblk.b_ext - 1; 0 < fextlen; chptr++, fextlen--)
 		{	/* Check each character in the extension except first which is the dot if ext exists at all */
 			if (WILDCARD != *chptr)
 			{	/* We see a char that isn't a wildcard character. If we've already seen our "o" file extension,
 				 * this char makes our requirement filetype impossible so raise an error.
-				 * TODO - more appropriate error
 				 */
 				if (seenfext || (OBJEXT != *chptr))
-					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILEPARSE, 2, objfilespec->str.len,
-						      objfilespec->str.addr);
-				seenfext = TRUE;	/* No return from rts_error() above so this is our object file type */
-			} else
-				seenwildcard = TRUE;
+					/* No return from this error */
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_FILEPARSE,
+						      2, objfilespec->str.len, objfilespec->str.addr,
+						      ERR_TEXT, 2, RTS_ERROR_TEXT("Unsupported filetype specified"));
+				seenfext = TRUE;
+			}
+		}
+	}
+	/* Do a simlar check for the file type */
+	if (0 != pblk.b_name)
+	{	/* A file name was specified (if not, tiz probably hard to find the file but that can be dealt with later).
+		 * Like in the above, the name must be comprised of valid chars for routine names.
+		 */
+		for (chptr = pblk.l_name, fnamlen = pblk.b_name; 0 < fnamlen; chptr++, fnamlen--)
+		{
+			if (WILDCARD != *chptr)
+			{	/* Substitute '%' for '_'. While this substitution is really only valid on the first char, only the
+				 * first char check allows "%" so a 2nd or later char check would fail the '%' substitution anyway.
+				 */
+				chr = ('_' == *chptr) ? '%' : *chptr;
+				/* We see a char that isn't a wildcard character. If this is the first character, it can be
+				 * alpha or percent. If the second or later character, it can be alphanumeric.
+				 */
+				if (((fnamlen != pblk.b_name) && !VALID_MNAME_NFCHAR(chr))	/* 2nd char or later check */
+				    || ((fnamlen == pblk.b_name) && !VALID_MNAME_FCHAR(chr)))	/* 1st char check */
+				{
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_FILEPARSE,
+						      2, objfilespec->str.len, objfilespec->str.addr,
+						      ERR_TEXT, 2, RTS_ERROR_TEXT("Filename is not a valid routine name"));
+				}
+			}
 		}
 	}
 	/* When specifying a non-wildcarded object file, it is possible for the file to have been removed, in which case we still
 	 * need to update its relinkctl entry (if exists) to notify other processes about the object's deletion.
-	 * TODO: should this see if given object exists in relinkctl file? If not, should it error or just ignore?
 	 */
-	if (!seenwildcard & seenfext)
-	{
+	if (!(pblk.fnb & F_WILD) & seenfext)
+	{	/* If no wildcards in path and saw the extension we want - no need to wash through zsearch() */
 		objdir.addr = pblk.l_dir;
 		objdir.len = pblk.b_dir;
 		linkctl = relinkctl_attach(&objdir);		/* Create/attach/open relinkctl file */
-		if (NULL == linkctl)
-			return;					/* Path doesn't exist - ignore */
-		rtnname.len = MIN(MAX_MIDENT_LEN, pblk.b_name); /* Avoid overflow */
+		if (NULL == linkctl)				/* Non-existant path and no associated relinkctl file */
+			/* Note this reference to errno depends on nothing in relinkctl_attach() doing anything to modify
+			 * errno after the realpath() call. No return from this error.
+			 */
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len, objfilespec->str.addr,
+				      errno);
+		/* What we do at this point depends on the following conditions:
+		 *
+		 * 1) If the specified file exists, we can add it to relinkctl file and/or update its cycle.
+		 * 2) If the file doesn't exist on disk but the routine is found in the relinkctl file, update cycle.
+		 * 3) If no file and no entry, just ignore it and do nothing (info error removed by request).
+		 */
+		STAT_FILE(tranbuf, &outbuf, stat_res);
+		if (-1 == stat_res)
+		{
+			if (ENOENT != errno)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objfilespec->str.len,
+					      objfilespec->str.addr, errno);
+			fileexists = FALSE;
+		} else
+			fileexists = TRUE;
+		rtnname.len = pblk.b_name;
 		rtnname.addr = pblk.l_name;
+		CONVERT_FILENAME_TO_RTNNAME(rtnname);	/* Set rtnname right before searching in relinkctl file */
+		assert(valid_mname(&rtnname));
+		COMPUTE_RELINKCTL_HASH(&rtnname, hash);
+		rec = relinkctl_find_record(linkctl, &rtnname, hash, &prev_hash_index);
+		if ((NULL == rec) && !fileexists)
+			return;					/* No file and no entry - ignore */
+		/* Either the file exists or the entry exists so add or update it */
 		rec = relinkctl_insert_record(linkctl, &rtnname);
-		RELINKCTL_CYCLE_INCR(linkctl, rec); 		/* Increment cycle indicating change to world */
+		RELINKCTL_CYCLE_INCR(rec, linkctl); 		/* Increment cycle indicating change to world */
 		return;
 	}
 	/* If we have a wildcarded request or one without the object filetype, reprocess the string with $ZSEARCH using our
@@ -127,35 +201,57 @@ void op_zrupdate(int argcnt, ...)
 	 * any file that doesn't have a ".o" extension.
 	 */
 	op_fnzsearch((mval *)&literal_null, STRM_ZRUPDATE, 0, &objpath);	/* Clear any existing cache */
-	while(TRUE)
+	for (fcnt = 0; ; fcnt++)
 	{
 		plen.p.pint = op_fnzsearch(objfilespec, STRM_ZRUPDATE, 0, &objpath);
 		if (0 == objpath.str.len)
-			/* End of file list */
+		{	/* End of file list */
+			if (0 == fcnt)
+				/* Still looking to process our first file - give no objects found message as a "soft" message
+				 * (INFO level message - supressed in other than direct mode)
+				 */
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) MAKE_MSG_INFO(ERR_FILEPARSE), 2, objfilespec->str.len,
+					      objfilespec->str.addr, ERR_TEXT, 2, RTS_ERROR_TEXT("No object files found"));
 			break;
+		}
 		/* The extension contains the extension-start character ('.') so we are looking for the extension '.o' hence
 		 * the length must be 2 and the 2nd char must be OBJEXT.
 		 */
 		if ((2 == plen.p.pblk.b_ext) && (OBJEXT == *(objpath.str.addr + plen.p.pblk.b_dir + plen.p.pblk.b_name + 1)))
-		{	/* This is (probably) an object file. Double check file is a file and not a directory */
+		{			/* This is (probably) an object file. Double check file is a file and not a directory */
 			memcpy(tranbuf, objpath.str.addr, objpath.str.len);	/* Need null terminated version for STAT */
-			tranbuf[objpath.str.len] = '\0';
+			tranbuf[objpath.str.len] = '\0';		/* Not guaranteed null termination from op_fnzsearch */
 			STAT_FILE(tranbuf, &outbuf, stat_res);
 			/* If either something happened to the file since op_fnzsearch() saw it or the file is not a file, then
 			 * ignore it.
 			 */
 			if ((-1 == stat_res) || !S_ISREG(outbuf.st_mode))
+			{
+				fcnt--;					/* Don't count files not found for whatever reason */
 				continue;
+			}
+			/* Before opening the relinkctl file, verify we actually do have a valid routine name */
+			rtnname.len = plen.p.pblk.b_name;
+			rtnname.addr = objpath.str.addr + plen.p.pblk.b_dir;
+			CONVERT_FILENAME_TO_RTNNAME(rtnname);		/* Set rtnname right before searching in relinkctl file */
+			if (!valid_mname(&rtnname))
+			{
+				fcnt--;
+				continue;				/* Ignore files that are invalid wildcard matches */
+			}
 			objdir.addr = objpath.str.addr;
 			objdir.len = plen.p.pblk.b_dir;
 			linkctl = relinkctl_attach(&objdir);		/* Create/attach/open relinkctl file */
 			if (NULL == linkctl)
-				continue;				/* Path disappeared - ignore */
-			rtnname.len = MIN(MAX_MIDENT_LEN, plen.p.pblk.b_name); 	/* Avoid overflow */
-			rtnname.addr = objpath.str.addr + plen.p.pblk.b_dir;
+			{
+				fcnt--;					/* Path disappeared - don't count it */
+				continue;
+			}
 			rec = relinkctl_insert_record(linkctl, &rtnname);
-			RELINKCTL_CYCLE_INCR(linkctl, rec); 		/* Increment cycle indicating change to world */
-		}
+			RELINKCTL_CYCLE_INCR(rec, linkctl); 		/* Increment cycle indicating change to world */
+		} else
+			fcnt--;						/* Don't count ignored files */
+
 	}
 }
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/open_object_file.c b/sr_unix/open_object_file.c
deleted file mode 100644
index 6e35c42..0000000
--- a/sr_unix/open_object_file.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************
- *								*
- *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
- *								*
- *	This source code contains the intellectual property	*
- *	of its copyright holder(s), and is made available	*
- *	under a license.  If you do not know the terms of	*
- *	the license, please stop and do not read further.	*
- *								*
- ****************************************************************/
-
-#include "mdef.h"
-
-#include <sys/types.h>
-#include "gtm_stat.h"
-#include "gtm_stdlib.h"
-#include "gtm_string.h"
-#include "gtm_limits.h"
-
-#include "cmd_qlf.h"
-#include "gtmio.h"
-#include "parse_file.h"
-
-GBLDEF char			tmp_object_file_name[MAX_FBUFF + 1];
-
-GBLREF command_qualifier	cmd_qlf;
-GBLREF char			object_file_name[];
-GBLREF short			object_name_len;
-GBLREF mident			module_name;
-
-error_def(ERR_FILEPARSE);
-error_def(ERR_OBJFILERR);
-
-/* Open object file - TODO: make into macro instead of routine */
-int open_object_file(const char *fname, int fflag)
-{
-	int		fdesc;
-
-	OPENFILE3(fname, fflag, 0666, fdesc);
-	return fdesc;
-}
-
-/* TODO - Move these routines to obj_file.c */
-/* Routine to create a temporary object file. This file is created in the directory it is supposed to reside in but is created
- * with a temporary name. When complete, it is renamed to what it was meant to be replacing the previous version.
- *
- * Parameters:
- *
- *   object_fname     - Character array of the object path/name.
- *   object_fname_len - Length of that array in bytes.
- *
- * Output:
- *   File descriptor for the open object file.
- */
-int mk_tmp_object_file(const char *object_fname, int object_fname_len)
-{
-	int	fdesc, status;
-	int	umask_creat, umask_orig;
-
-	/* TODO Verify addition of XXXXXX doesn't exceed dimensions of array */
-	memcpy(tmp_object_file_name, object_fname, object_fname_len);
-        memcpy(&tmp_object_file_name[object_fname_len], "XXXXXX", 7);	/* Includes null terminator */
-	fdesc = mkstemp(tmp_object_file_name);
-	if (FD_INVALID == fdesc)
-	{
-		printf("tmp_object_file_name: %s\n", tmp_object_file_name);
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_fname_len, object_fname, errno);
-	}
-	umask_orig = umask(000);	/* Determine umask (destructive) */
-	(void)umask(umask_orig);	/* Reset umask */
-	umask_creat = 0666 & ~umask_orig;
-	/* TODO: set protections appropriately (if this isn't it) */
-	FCHMOD(fdesc, umask_creat);
-        return fdesc;
-}
-
-void rename_tmp_object_file(const char *object_fname)
-{
-	rename(tmp_object_file_name, object_fname);	/* TODO - Handle error (SEE) and make into macro instead of routine */
-}
-
-/*
- * Inputs: cmd_qlf.object_file, module_name
- * Outputs: object_file_name, object_name_len
- */
-void init_object_file_name(void)
-{
-	int		status, rout_len;
-	char		obj_name[SIZEOF(mident_fixed) + 5];
-	mstr		fstr;
-	parse_blk	pblk;
-
-	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 = (int)module_name.len;
-	memcpy(&obj_name[0], module_name.addr, rout_len);
-	memcpy(&obj_name[rout_len], DOTOBJ, SIZEOF(DOTOBJ));    /* includes null terminator */
-	pblk.def1_size = rout_len + SIZEOF(DOTOBJ) - 1;         /* Length does not include null terminator */
-	pblk.def1_buf = obj_name;
-	status = parse_file(&fstr, &pblk);
-	if (0 == (status & 1))
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status);
-
-	object_name_len = pblk.b_esl;
-	object_file_name[object_name_len] = '\0';
-}
diff --git a/sr_unix/parse_file.h b/sr_unix/parse_file.h
index 0dffb0d..f05a9b4 100644
--- a/sr_unix/parse_file.h
+++ b/sr_unix/parse_file.h
@@ -54,8 +54,8 @@ typedef struct plength_struct
 #define F_HAS_DIR	4	/* 0x04 If file has explicit directory path */
 #define F_WILD_NAME	8	/* 0x08 If there is a wild card character in the name */
 #define F_WILD_DIR	16	/* 0x10 If there is a wild card character in the directory */
-#define F_WILD		24	/* 0x20 If there is a wild card character in the result */
-#define F_HAS_NODE	32	/* 0x40 If there is a node specification on the front - db opening only */
+#define F_WILD		24	/* 0x18 If there is a wild card character in the result (dir or name) */
+#define F_HAS_NODE	32	/* 0x20 If there is a node specification on the front - db opening only */
 
 #define V_HAS_EXT	0	/* Bit offsets for F_ constants */
 #define V_HAS_NAME	1
@@ -64,7 +64,9 @@ typedef struct plength_struct
 #define V_WILD_DIR	4
 #define V_HAS_NODE	5	/* DB opening only */
 
-#define F_SYNTAXO	1	/* SYNTAX ONLY */
+#define F_SYNTAXO	1	/* SYNTAX ONLY - Otherwise checks on directory existence returning ERR_FILENOTFOUND if
+				 * directory does not exist or is not a directory.
+				 */
 #define F_PARNODE	2	/* Look for a node specification - db opening only */
 
 int4 parse_file(mstr *file, parse_blk *pblk);
diff --git a/sr_port/md5_digest2hex.h b/sr_unix/probecrit_rec.h
similarity index 53%
rename from sr_port/md5_digest2hex.h
rename to sr_unix/probecrit_rec.h
index fe3322c..d1f29ae 100644
--- a/sr_port/md5_digest2hex.h
+++ b/sr_unix/probecrit_rec.h
@@ -9,13 +9,20 @@
  *								*
  ****************************************************************/
 
-#ifndef MD5_DIGEST2HEX_INCLUDED
-#define MD5_DIGEST2HEX_INCLUDED
+#ifndef PROBECRIT_REC_H_INCLUDED
+#define PROBECRIT_REC_H_INCLUDED
+#define	TAB_PROBECRIT_REC(A,B,C)	A,
+enum probecrit_rec_type
+{
+#	include "tab_probecrit_rec.h"
+	n_probecrit_rec_types
+};
+#undef TAB_PROBECRIT_REC
 
-#include "md5hash.h"
-
-#define MD5_HEXSTR_LENGTH	33
-
-void md5_digest2hex(char hexstr[MD5_HEXSTR_LENGTH], const unsigned char digest[MD5_DIGEST_LENGTH]);
-
-#endif /* MD5_DIGEST2HEX_INCLUDED */
+typedef struct probecrit_rec_struct
+{
+#	define	TAB_PROBECRIT_REC(A,B,C)	gtm_uint64_t	A;
+#	include "tab_probecrit_rec.h"
+} probecrit_rec_t;
+#undef TAB_PROBECRIT_REC
+#endif
diff --git a/sr_unix/rel_latch.c b/sr_unix/rel_latch.c
new file mode 100644
index 0000000..6cfa572
--- /dev/null
+++ b/sr_unix/rel_latch.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 DEBUG
+#include "gtm_unistd.h"	/* for "getpid" */
+#endif
+
+#include "interlock.h"
+
+GBLREF	volatile int4	fast_lock_count;		/* Stop interrupts while we have our parts exposed */
+GBLREF	uint4		process_id;
+
+/* Grab a latch. If cannot get it, return FALSE, else TRUE. */
+void	rel_latch(sm_global_latch_ptr_t latch)
+{
+	++fast_lock_count;	/* Disable interrupts (i.e. wcs_stale) for duration to avoid potential deadlocks */
+	assert(process_id == getpid());	/* make sure "process_id" global variable is reliable (used below in RELEASE_SWAPLOCK) */
+	RELEASE_SWAPLOCK(latch);
+	--fast_lock_count;
+	assert(0 <= fast_lock_count);
+}
diff --git a/sr_unix/relinkctl.c b/sr_unix/relinkctl.c
index 3ea1596..9cb1429 100644
--- a/sr_unix/relinkctl.c
+++ b/sr_unix/relinkctl.c
@@ -13,6 +13,9 @@
 
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <sys/shm.h>
+
+#include "gtm_ipc.h"
 #include "gtm_limits.h"
 #include "gtm_fcntl.h"
 #include "gtm_unistd.h"
@@ -26,31 +29,46 @@
 #include "gtmio.h"
 #include <rtnhdr.h>
 #include "relinkctl.h"
-#include "zhist.h"
-#include "md5hash.h"
-#include "md5_digest2hex.h"
-#include "stringpool.h"
-
-/*
- * This module contains routines that maintain autorelink 'relinkctl' structures.
+#include "mmrhash.h"
+#include "iosp.h"
+#include "do_shmat.h"
+#include "hashtab.h"
+#include "ipcrmid.h"
+#include "eintr_wrappers.h"
+#include "stack_frame.h"
+#ifdef DEBUG
+#  include "wbox_test_init.h"
+#  include "toktyp.h"		/* needed by "valid_mname.h" */
+#  include "valid_mname.h"
+#endif
+#include "arlinkdbg.h"
+#include "min_max.h"
+#include "rtnobj.h"
+#include "gtmmsg.h"
+#include "hugetlbfs_overrides.h"	/* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
+#include "gtm_permissions.h"
+
+/* This module contains routines that maintain autorelink 'relinkctl' structures.
  * TODO - add description
  */
 
 DEBUG_ONLY(GBLDEF int	saved_errno;)
-GBLREF	uint4	process_id;
+GBLREF	uint4		process_id;
+GBLREF	rtn_tabent	*rtn_names, *rtn_names_end;
+GBLREF	stack_frame	*frame_pointer;
+OS_PAGE_SIZE_DECLARE
 
-STATICFNDCL void relinkctl_map(open_relinkctl_sgm *linkctl, uint4 n_records);
+STATICFNDCL void relinkctl_map(open_relinkctl_sgm *linkctl);
 STATICFNDCL void relinkctl_unmap(open_relinkctl_sgm *linkctl);
-STATICFNDCL uint4 relinkctl_recs2map(uint4 n_records);
 STATICFNDCL int relinkctl_fcntl_lock(int fd, int l_type);
-STATICFNDCL void relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name);
 STATICFNDCL void relinkctl_delete(open_relinkctl_sgm *linkctl);
 
-#define ISSUE_RELINKCTLERR_SYSCALL(ZRO_ENTRY_NAME, LIBCALL)							\
-	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME),		\
-		      ERR_SYSCALL, 5, LEN_AND_STR(LIBCALL), CALLFROM, DEBUG_ONLY(saved_errno = )errno)
-
+error_def(ERR_PERMGENFAIL);
 error_def(ERR_RELINKCTLERR);
+error_def(ERR_RELINKCTLFULL);
+error_def(ERR_REQRLNKCTLRNDWN);
+error_def(ERR_RLNKCTLRNDWNFL);
+error_def(ERR_RLNKCTLRNDWNSUC);
 error_def(ERR_SYSCALL);
 error_def(ERR_TEXT);
 
@@ -65,19 +83,20 @@ error_def(ERR_TEXT);
 open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
 {
 	open_relinkctl_sgm 	*linkctl, *new_link;
-	int			len, save_errno;
+	int			i, len, save_errno;
 	mstr			objdir;
 	char			pathin[GTM_PATH_MAX], resolvedpath[GTM_PATH_MAX];	/* Includes null terminator char */
 	char			*pathptr;
 	boolean_t		pathfound;
+	char			relinkctl_path[GTM_PATH_MAX], *ptr;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
 	/* Directory name normalization - the directory name must always be the same for purposes of mapping the relinkctl
 	 * file. To accomplish this takes two steps:
 	 *    1. Use realpath() on the directory name to disambiguate it.
-	 *    2. Remove trailing slash(es) in the object directory name.
+	 *    2. Remove trailing slash(es) so the object directory name.
 	 */
 	pathfound = TRUE;				/* Assume we'll find the path */
 	assert(GTM_PATH_MAX > obj_container_name->len);	/* Should have been checked by our caller */
@@ -86,28 +105,54 @@ open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
 	pathptr = realpath(pathin, resolvedpath);
 	if (NULL == pathptr)
 	{
-		pathfound = FALSE;			/* Path no longer exists - use our best attempt to find it */
-		pathptr = pathin;
+		if (ENOENT == (save_errno = errno))	/* Note assignment */
+		{
+			pathfound = FALSE;		/* Path no longer exists - use our best attempt to find it */
+			pathptr = pathin;
+		} else
+			/* This error is appropriate here as the directory was checked in the caller before coming here
+			 * so this error is "just-in-case".
+			 */
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("realpath()"), CALLFROM,
+				      save_errno);
 	}
 	objdir.addr = pathptr;
 	objdir.len = strlen(pathptr);
+	assert(objdir.len < ARRAYSIZE(resolvedpath));
 	while ((1 < objdir.len) && ('/' == *(objdir.addr + objdir.len - 1)))
 		objdir.len--;
-	/* Now look the directory up in our list to see if we have it or not already */
+	/* Now look the directory up in our list to see if we have it or not already*/
 	for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
 	{
 		if (MSTR_EQ(&objdir, &linkctl->zro_entry_name))
 			return linkctl;
 	}
-	/* If realpath() didn't find the path and we don't already have it open, don't create a relinkctl file for it */
+	/* If realpath() didn't find the path and we don't already have it open, don't create a relinkctl file for it. Note if
+	 * the caller is op_zrupdate(), very shortly we are going to try to use the errno value set above in realpath(). If
+	 * anything gets added to this module between the realpath() above and here, a different mechanism for passing errno
+	 * needs to be found.
+	 */
 	if (!pathfound)
 		return NULL;
 	/* Not already open */
-	new_link = malloc(SIZEOF(open_relinkctl_sgm));
-	new_link->zro_entry_name = objdir;
-	s2pool(&new_link->zro_entry_name);		/* Migrate string to stringpool for safe keeping */
+	len = relinkctl_get_key(relinkctl_path, &objdir) + 1;	/* + 1 for trailing null in relinkctl_path */
+	assert(len <= ARRAYSIZE(relinkctl_path));
+	new_link = malloc(SIZEOF(open_relinkctl_sgm) + objdir.len + 1 + len);	/* + 1 for trailing null in zro_entry_name */
+	memset(new_link, 0, SIZEOF(open_relinkctl_sgm));
+	new_link->zro_entry_name.len = objdir.len;
+	new_link->zro_entry_name.addr = ptr = (char *)(new_link + 1);
+	memcpy(ptr, objdir.addr, objdir.len);
+	ptr += objdir.len;
+	*ptr++ = '\0';	/* trailing null for "new_link->zro_entry_name" */
+	new_link->relinkctl_path = ptr;
+	memcpy(ptr, relinkctl_path, len);
+	assert('\0' == new_link->relinkctl_path[len - 1]);
+	for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+		new_link->rtnobj_shmid[i] = INVALID_SHMID;
 	/* Open + map structure */
-	relinkctl_open(new_link);
+	relinkctl_open(new_link);	/* initializes new_link->fd, new_link->hdr, new_link->n_records,
+					 * new_link->rec_base, new_link->shm_hashbase and new_link->locked
+					 */
 	/* Add to open list */
 	new_link->next = TREF(open_relinkctl_list);
 	TREF(open_relinkctl_list) = new_link;
@@ -115,169 +160,362 @@ open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name)
 #	else
 	return NULL;
 #	endif
-
 }
 
-/*
- * Given linkctl->zro_entry_name -- an object directory in $ZROUTINES -- open() and mmap() relink ctl structure, thus
- * filling in linkctl->fd and linkctl->hdr.
+/* Routine to open and mmap a relinkctl file for a given $ZROUTINES object directory.
+ *
+ * Parameter:
+ *    linkctl - open_relinkctl_sgm (process private) block describing shared (mmap'd) entry and supplying the path/name
+ *              of the relinkctl file comprised of both static and hashed directory name values for uniqueness.
+ *
+ * Returns:
+ *    Various fields in linkctl (fd, hdr).
+ *
  * The control structure should be both readable *and* writable by anything that can read the object directory.
  */
 void relinkctl_open(open_relinkctl_sgm *linkctl)
 {
-	int		fd, status, save_errno;
-	int		umask_creat, umask_orig;
-	char		relinkctl_path[GTM_PATH_MAX];
-	struct stat     stat_buf;
+#	ifdef AUTORELINK_SUPPORTED
+	int			fd, i, j, rc, save_errno, shmid, status, retries;
+	struct stat     	stat_buf;
+	size_t			shm_size;
+	boolean_t		is_mu_rndwn_rlnkctl, shm_removed;
+	relinkshm_hdr_t		*shm_base;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	relinkctl_data		*hdr;
+	char			errstr[256];
+	struct stat		dir_stat_buf;
+	int			stat_res;
+	int			user_id;
+	int			group_id;
+	int			perm;
+	struct perm_diag_data	pdd;
+	struct shmid_ds		shmstat;
+	DCL_THREADGBL_ACCESS;
 
-#	ifdef USHBIN_SUPPORTED
+	SETUP_THREADGBL_ACCESS;
 	linkctl->hdr = NULL;
 	/* open the given relinkctl file */
-	relinkctl_get_key(relinkctl_path, &linkctl->zro_entry_name);
-	DBGARLNK((stderr, "relinkctl_open: Opening relinkctl file %s for entry %.*s\n", relinkctl_path,
-		  linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr));
-	/* RW permissions for owner and others as determined by umask. */
-	umask_orig = umask(000);	/* determine umask (destructive) */
-	(void)umask(umask_orig);	/* reset umask */
-	umask_creat = 0666 & ~umask_orig;
+	DBGARLNK((stderr, "relinkctl_open: pid = %d : Opening relinkctl file %s for entry %.*s\n", getpid(),
+		linkctl->relinkctl_path, linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr));
 	/* Anybody that has read permissions to the object container should have write permissions to the relinkctl file */
-	fd = OPEN3(relinkctl_path, O_CREAT | O_RDWR, umask_creat);
-	/* TODO: get permissions right. see comment above . important */
-	/* Do we want a relinkctl sitting around for $gtm_dist? */
-	if (FD_INVALID == fd)
-		ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "open()");
-	linkctl->fd = fd;
-	/* If file is newly created, initialize it */
-	FSTAT_FILE(fd, &stat_buf, status);
-	if (0 != status)
-		ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "fstat()");
-	if (0 == stat_buf.st_size)
+	retries = 0;
+	is_mu_rndwn_rlnkctl = TREF(is_mu_rndwn_rlnkctl);
+	do
 	{
+		assert('\0' == linkctl->zro_entry_name.addr[linkctl->zro_entry_name.len]);	/* needed for STAT_FILE */
+		STAT_FILE(linkctl->zro_entry_name.addr, &dir_stat_buf, stat_res);
+		if (-1 == stat_res)
+		{
+			SNPRINTF(errstr, SIZEOF(errstr), "stat() of file %s failed", linkctl->zro_entry_name.addr);
+			ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, errno);
+		}
+		if (gtm_permissions(&dir_stat_buf, &user_id, &group_id, &perm, PERM_IPC, &pdd) < 0)
+		{
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name),
+					ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("relinkctl"),
+					RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+		}
+		/* Attempt to create file with desired permissions */
+		fd = OPEN3(linkctl->relinkctl_path, O_CREAT | O_RDWR | O_EXCL, perm);
+		/* If file created, set owner/group, if needed */
+		if ((FD_INVALID != fd)
+			&& (((-1 != user_id) && (user_id != stat_buf.st_uid))
+				|| ((-1 != group_id) && (group_id != stat_buf.st_gid)))
+			&& (-1 == fchown(fd, user_id, group_id)))
+		{
+			save_errno = errno;
+			CLOSEFILE_RESET(fd, rc);
+			SNPRINTF(errstr, SIZEOF(errstr), "fchown() of file %s failed", linkctl->relinkctl_path);
+			ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+		}
+		if ((FD_INVALID == fd) && (errno == EEXIST))
+		{	/* file already existed, open existing */
+			fd = OPEN3(linkctl->relinkctl_path, O_CREAT | O_RDWR, 0);
+		}
+		if (FD_INVALID == fd)
+		{
+			SNPRINTF(errstr, SIZEOF(errstr), "open() of file %s failed", linkctl->relinkctl_path);
+			ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, errno);
+		}
+
+		linkctl->fd = fd;
 		relinkctl_lock_exclu(linkctl);
+
 		FSTAT_FILE(fd, &stat_buf, status);
 		if (0 != status)
 		{
-			relinkctl_unlock_exclu(linkctl);
-			ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "fstat()");
+			save_errno = errno;
+			CLOSEFILE_RESET(fd, rc);
+			SNPRINTF(errstr, SIZEOF(errstr), "fstat() of file %s failed", linkctl->relinkctl_path);
+			ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
 		}
-		if (0 == stat_buf.st_size)
+		if (RELINKCTL_MMAP_SZ != stat_buf.st_size)
 		{
-			/* TODO: fix file extension so we don't need to preallocate so much space */
-			ftruncate(fd, SIZEOF(relinkctl_data) + 1000000 * SIZEOF(relinkrec_t));
-			relinkctl_map(linkctl, 0);
-			linkctl->hdr->n_records = 0;	/* what happens if kill -9'd between ftruncate and n_records = 0? */
-			SET_LATCH_GLOBAL(&linkctl->hdr->attach_latch, LOCK_AVAILABLE);
+			DBGARLNK((stderr, "relinkctl_open: file size = %d\n", stat_buf.st_size));
+			if (RELINKCTL_MMAP_SZ != stat_buf.st_size)
+			{
+				FTRUNCATE(fd, RELINKCTL_MMAP_SZ, rc);
+				if (0 != rc)
+				{
+					save_errno = errno;
+					relinkctl_unlock_exclu(linkctl);
+					SNPRINTF(errstr, SIZEOF(errstr), "ftruncate() of file %s failed", linkctl->relinkctl_path);
+					ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+				}
+			}
+		}
+		relinkctl_map(linkctl);	/* linkctl->hdr is now accessible */
+		hdr = linkctl->hdr;
+		if (hdr->file_deleted)
+		{	/* Some other process concurrently opened and closed/deleted the relinkctl file while
+			 * we were still inside relinkctl_open. Reattach to new file (create it if necessary)
+			 * instead of using the current fd as this wont be visible to other new processes.
+			 */
+			DBGARLNK((stderr, "relinkctl_open: file_deleted = 1. Retrying open.\n"));
+			relinkctl_unlock_exclu(linkctl);
 			relinkctl_unmap(linkctl);
+			assert(NULL == linkctl->hdr);
+			assertpro(16 > retries++);	/* too many loops is not practically possible. prevent infinite loops */
+			continue;
+		}
+		shm_size = RELINKCTL_SHM_SIZE;
+		ADJUST_SHM_SIZE_FOR_HUGEPAGES(shm_size, shm_size); /* second parameter "shm_size" is adjusted size */
+		if (hdr->initialized)
+		{	/* Not creator of shared memory. Need to attach to shared memory.
+			 * Need lock (already obtained) to prevent interaction with concurrent initialization, nattached = 0.
+			 */
+			shmid = hdr->relinkctl_shmid;
+			DBGARLNK((stderr, "relinkctl_open: file already initialized : pre-increment hdr->nattached = %d"
+				" : shmid = %d\n", hdr->nattached, shmid));
+			assert(INVALID_SHMID != shmid);
+			assert(!hdr->file_deleted);
+			hdr->nattached++;
+			if (!is_mu_rndwn_rlnkctl)
+				relinkctl_unlock_exclu(linkctl);
+			if (-1 == (sm_long_t)(shm_base = (relinkshm_hdr_t *)do_shmat(shmid, 0, 0)))
+			{
+				save_errno = errno;
+				shm_removed = SHM_REMOVED(save_errno);
+				/* If shm has been removed, then direct one to use MUPIP RUNDOWN -RELINKCTL */
+				if (!shm_removed || !is_mu_rndwn_rlnkctl)
+				{
+					if (!is_mu_rndwn_rlnkctl)
+						relinkctl_lock_exclu(linkctl);
+					hdr->nattached--;
+					relinkctl_unlock_exclu(linkctl);
+					relinkctl_unmap(linkctl);
+					if (!shm_removed)
+					{
+						SNPRINTF(errstr, SIZEOF(errstr), "shmat() failed for "
+							"shmid=%d shmsize=%llu [0x%llx]", shmid, shm_size, shm_size);
+						ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+					} else
+						rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REQRLNKCTLRNDWN, 2,
+									RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+				} else
+				{	/* This is MUPIP RUNDOWN -RELINKCTL and shm is removed. Run this relinkctl file down. */
+					DBGARLNK((stderr, "relinkctl_open: Set hdr->initialized to FALSE\n"));
+					hdr->initialized = FALSE;
+				}
+			}
 		}
+		if (!hdr->initialized)
+		{
+			DBGARLNK((stderr, "relinkctl_open: file first open\n"));
+			hdr->n_records = 0;
+			/* Create shared memory to store hash buckets of routine names for faster search in relinkctl file */
+			assert(RELINKCTL_HASH_BUCKETS == getprime(RELINKCTL_MAX_ENTRIES));
+			shmid = shmget(IPC_PRIVATE, shm_size, RWDALL | IPC_CREAT);
+			if (-1 == shmid)
+			{
+				save_errno = errno;
+				relinkctl_delete(linkctl);
+				relinkctl_unlock_exclu(linkctl);
+				relinkctl_unmap(linkctl);
+				SNPRINTF(errstr, SIZEOF(errstr), "shmget() failed for shmsize=%llu [0x%llx]", shm_size, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			if (-1 == shmctl(shmid, IPC_STAT, &shmstat))
+			{
+				save_errno = errno;
+				relinkctl_delete(linkctl);
+				relinkctl_unlock_exclu(linkctl);
+				relinkctl_unmap(linkctl);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "shmctl(IPC_STAT) failed for shmid=%d shmsize=%llu [0x%llx]",
+					shmid, shm_size, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			/* change group and permissions */
+			if ((-1 != user_id) && (user_id != shmstat.shm_perm.uid))
+				shmstat.shm_perm.uid = user_id;
+			if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid))
+				shmstat.shm_perm.gid = group_id;
+			shmstat.shm_perm.mode = perm;
+			if (-1 == shmctl(shmid, IPC_SET, &shmstat))
+			{
+				save_errno = errno;
+				relinkctl_delete(linkctl);
+				relinkctl_unlock_exclu(linkctl);
+				relinkctl_unmap(linkctl);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "shmctl(IPC_SET) failed for shmid=%d shmsize=%llu [0x%llx]",
+					shmid, shm_size, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			/* Initialize shared memory header */
+			if (-1 == (sm_long_t)(shm_base = (relinkshm_hdr_t *)do_shmat(shmid, 0, 0)))
+			{
+				save_errno = errno;
+				relinkctl_delete(linkctl);
+				relinkctl_unlock_exclu(linkctl);
+				relinkctl_unmap(linkctl);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "shmat() failed for shmid=%d shmsize=%llu [0x%llx]",
+					shmid, shm_size, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			hdr->relinkctl_shmid = shmid;
+			hdr->relinkctl_shmlen = shm_size;
+			assert(ARRAYSIZE(shm_base->relinkctl_fname) > strlen(linkctl->relinkctl_path));
+			assert(0 == ((UINTPTR_T)shm_base % 8));
+			assert(0 == (SIZEOF(relinkshm_hdr_t) % SIZEOF(uint4)));	/* assert SIZEOF(*sm_uint_ptr_t) alignment */
+			memset(shm_base, 0, shm_size);
+			strcpy(shm_base->relinkctl_fname, linkctl->relinkctl_path);
+			shm_base->min_shm_index = TREF(relinkctl_shm_min_index);
+			shm_base->rtnobj_min_shm_index = NUM_RTNOBJ_SHM_INDEX;
+			shm_base->rtnobj_max_shm_index = 0;
+			shm_base->rtnobj_shmid_cycle = 0;
+			shm_base->rndwn_adjusted_nattch = FALSE;
+			DEBUG_ONLY(shm_base->skip_rundown_check = FALSE;)
+			for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+			{
+				rtnobj_shm_hdr = &shm_base->rtnobj_shmhdr[i];
+				rtnobj_shm_hdr->rtnobj_shmid = INVALID_SHMID;
+				rtnobj_shm_hdr->rtnobj_min_free_index = NUM_RTNOBJ_SIZE_BITS;
+				for (j = 0; j < NUM_RTNOBJ_SIZE_BITS; j++)
+				{
+					rtnobj_shm_hdr->freeList[j].fl = NULL_RTNOBJ_SM_OFF_T;
+					rtnobj_shm_hdr->freeList[j].bl = NULL_RTNOBJ_SM_OFF_T;
+				}
+			}
+			SET_LATCH_GLOBAL(&shm_base->relinkctl_latch, LOCK_AVAILABLE);
+			hdr->nattached = 1;
+			hdr->zro_entry_name_len = MIN(linkctl->zro_entry_name.len, ARRAYSIZE(hdr->zro_entry_name) - 1);
+			memcpy(hdr->zro_entry_name, linkctl->zro_entry_name.addr, hdr->zro_entry_name_len);
+			hdr->zro_entry_name[hdr->zro_entry_name_len] = '\0';
+			/* shared memory initialization complete */
+			hdr->initialized = TRUE;
+			relinkctl_unlock_exclu(linkctl);
+		} else if (is_mu_rndwn_rlnkctl)
+			relinkctl_unlock_exclu(linkctl);
+		assert(!linkctl->locked);
+		assert(0 == ((UINTPTR_T)shm_base % 8));
+		assert(0 == (SIZEOF(relinkshm_hdr_t) % SIZEOF(uint4)));	/* assert SIZEOF(*sm_uint_ptr_t) alignment */
+#		ifdef DEBUG
+		if (TREF(gtm_autorelink_keeprtn))
+			shm_base->skip_rundown_check = TRUE;
+#		endif
+		linkctl->shm_hashbase = (sm_uint_ptr_t)(sm_uc_ptr_t)(shm_base + 1);
+			/* skip past shm header to reach hash array start */
+		assert(0 == ((UINTPTR_T)linkctl->shm_hashbase % 8));	/* assert each section is 8-byte aligned at least */
+		assert(1 == RELINKCTL_HASH_BUCKETS % 2); /* RELINKSHM_RTNHASH_SIZE definition relies on this for 8-byte alignment */
+		linkctl->rec_base = (relinkrec_t *)((sm_uc_ptr_t)linkctl->shm_hashbase + RELINKSHM_RTNHASH_SIZE);
+		assert(128 >= SIZEOF(relinkrec_t));	/* or else adjust CACHELINE_PAD_COND filler downwards */
+		assert(0 == ((UINTPTR_T)linkctl->rec_base % 8));	/* assert each section is 8-byte aligned at least */
+		break;
+	} while (TRUE);
+#	endif
+}
+
+#ifdef AUTORELINK_SUPPORTED
+/* This is called from processes that already have "linkctl" attached but have not done an increment of "linkctl->hdr->nattached".
+ * Example is a jobbed off process in ojstartchild.c
+ */
+void relinkctl_incr_nattached(void)
+{
+	open_relinkctl_sgm *linkctl;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+	{
+		relinkctl_lock_exclu(linkctl);
+		DBGARLNK((stderr, "relinkctl_incr_nattached : pid = %d : file %s : pre-incr hdr->nattached = %d\n",
+			  getpid(), linkctl->relinkctl_path, linkctl->hdr->nattached));
+		assert(linkctl->hdr->nattached);
+		linkctl->hdr->nattached++;
 		relinkctl_unlock_exclu(linkctl);
 	}
-	/* Do an small mapping in order to read n_records, then map the full file */
-	relinkctl_map(linkctl, 0);
-	relinkctl_ensure_fullmap(linkctl);
-	/* Need lock to prevent interaction with concurrent initialization, nattached = 0 */
-	relinkctl_lock_exclu(linkctl);
-	linkctl->hdr->nattached++;
-	/*sprintf(buff, "%s - incremented. nattached = %d", linkctl->zro_entry_name, linkctl->hdr->nattached);
-	send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(buff));*/
- 	/*send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
-	  LEN_AND_LIT("%s - incremented. nattached = %d")); debugging TODO*/
-	relinkctl_unlock_exclu(linkctl);
-	/* TODO: when to close? with ZGOTO 0? or never bother? */
-#	endif
 }
 
 /* Routine to generate unique key for a $ZROUTINES entry name used to create relinkctl file for that entry in the directory
  * $gtm_linktmpdir (e.g. /testarea1/gtm/temp --> $gtm_linktmpdir/gtm-relinkctl-d0f3d074c724430bc1c7679141b96411).
  * Theoretically, we'd need a scheme to resolve hash collisions. Say, append -<collision_id> to the key.
- * But since this is MD5, we can assume a collision will never happen in practice, so we do not handle the extremely
- * unlikely event of an MD5 hash collision for the few $ZROUTINES entries used by processes using the same $gtm_linktmpdir
- * value.
+ * But since this is 128-bit MurmurHash3, we can assume a collision will never happen in practice, so we do not
+ * handle the extremely unlikely event of a hash collision for the few $ZROUTINES entries used by processes using
+ * the same $gtm_linktmpdir value.
  *
  * Parameters:
  *
- *   key            - Generated as $gtm_linktmpdir/gtm-relinkctl-<md5>. Buffer should be GTM_PATH_MAX bytes (output).
+ *   key            - Generated as $gtm_linktmpdir/gtm-relinkctl-<hash>. Buffer should be GTM_PATH_MAX bytes (output).
  *   zro_entry_name - Address of mstr containing the fully expanded zroutines entry directory name.
  */
-#ifdef USHBIN_SUPPORTED
-STATICFNDEF void relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name)
+int relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name)
 {
-	cvs_MD5_CTX	md5context;
-	unsigned char	digest[MD5_DIGEST_LENGTH];
-	char		hexstr[MD5_HEXSTR_LENGTH];
+	gtm_uint16	hash;
+	unsigned char	hexstr[33];
 	int		keylen;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	cvs_MD5Init(&md5context);
-	cvs_MD5Update(&md5context, (const unsigned char *)zro_entry_name->addr, zro_entry_name->len);
-	cvs_MD5Final(digest, &md5context);
-	md5_digest2hex(hexstr, digest);
-	/* Improve efficiency - use memcpy to build string and provide better max-length checking than an assert */
+	gtmmrhash_128(zro_entry_name->addr, zro_entry_name->len, 0, &hash);
+	gtmmrhash_128_hex(&hash, hexstr);
+	hexstr[32] = '\0';
+	/* TODO: Improve efficiency - use memcpy to build string and provide better max-length checking than an assert */
 	keylen = SNPRINTF(&key[0], GTM_PATH_MAX - 1, "%.*s/gtm-relinkctl-%s", (TREF(gtm_linktmpdir)).len,
 			  (TREF(gtm_linktmpdir)).addr, hexstr);
 	assert((0 < keylen) && (GTM_PATH_MAX > keylen));
+	return keylen;
 }
-#endif
 
 /**
  * Relinkctl mmap-related methods
  */
 
-/*
- * Remap, if entire array of relink records is not mapped.
- */
-void relinkctl_ensure_fullmap(open_relinkctl_sgm *linkctl)
-{
-	uint4	nrec;
-
-#	ifdef USHBIN_SUPPORTED
-	nrec = linkctl->hdr->n_records;
-	if (nrec >= relinkctl_recs2map(linkctl->n_records))
-	{
-		relinkctl_unmap(linkctl);
-		relinkctl_map(linkctl, nrec);
-	}
-	linkctl->n_records = nrec;
-#	endif
-}
-
-/*
- * Map at least n_records, currently known number of entries.
+/* Routine to map at least n_records, currently known number of entries.
+ *
+ * Parameter:
+ *      linkctl - addr of process-private block describing the shared file.
  *
  * Fills in:
  * 	linkctl->hdr
  * 	linkctl->n_records
- * 	linkctl->rec_base
  */
-#ifdef USHBIN_SUPPORTED
-STATICFNDEF void relinkctl_map(open_relinkctl_sgm *linkctl, uint4 n_records)
+STATICFNDEF void relinkctl_map(open_relinkctl_sgm *linkctl)
 {
 	sm_uc_ptr_t	addr;
-	size_t		mapsz;
 
-	mapsz = SIZEOF(relinkctl_data) + (relinkctl_recs2map(n_records) * SIZEOF(relinkrec_t));
-	addr = (sm_uc_ptr_t)mmap(NULL, mapsz, (PROT_READ + PROT_WRITE), MAP_SHARED, linkctl->fd, 0);
+	assert(NULL == linkctl->hdr);
+	addr = (sm_uc_ptr_t)mmap(NULL, RELINKCTL_MMAP_SZ, (PROT_READ + PROT_WRITE), MAP_SHARED, linkctl->fd, 0);
 	if (MAP_FAILED == addr)
-		ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "mmap()");
+		ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, "mmap()", errno);
 	linkctl->hdr = (relinkctl_data *)addr;
-	linkctl->n_records = n_records;
-	linkctl->rec_base = &linkctl->hdr->base[0];
+	linkctl->n_records = 0;
 }
 
+/* Routine similar to relink_map except UNMAPs the file */
 STATICFNDEF void relinkctl_unmap(open_relinkctl_sgm *linkctl)
 {
-	/* TODO */
-}
+	sm_uc_ptr_t	addr;
+	int		rc;
 
-/*
- * We don't want to repeatedly re-mmap the file, so given some minimum number of records we need to map,
- * compute a larger number to accomodate before we need to remap.
- */
-STATICFNDEF uint4 relinkctl_recs2map(uint4 n_records)
-{
-	/* TODO: Improve - right now, limited to fixed initial size */
-	return 1000000;
-	/* return n_records + 1; - This causes excessive remapping - pick a better increment */
+	addr = (sm_uc_ptr_t)linkctl->hdr;
+	munmap(addr, RELINKCTL_MMAP_SZ); /* If munmap errors, it seems better to move on than stop for a non-critical error */
+	linkctl->hdr = NULL;
+	linkctl->n_records = 0;
+	CLOSEFILE_RESET(linkctl->fd, rc);
 }
 #endif
 
@@ -285,8 +523,7 @@ STATICFNDEF uint4 relinkctl_recs2map(uint4 n_records)
  * Exclusive locking methods controlling WRITE access to relinkctl control files.
  */
 
-/*
- * Routine to exclusively lock the relinkctl file.
+/* Routine to exclusively lock the relinkctl file.
  *
  * Parameter:
  *
@@ -296,21 +533,30 @@ void relinkctl_lock_exclu(open_relinkctl_sgm *linkctl)
 {
 	int	status;
 
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
+	assert(!linkctl->locked);
+	if (linkctl->locked)
+		return;
 	status = relinkctl_fcntl_lock(linkctl->fd, F_WRLCK);
-	assert(0 == status);	/* TODO: Deal with error */
+	if (-1 == status)
+		ISSUE_RELINKCTLERR_TEXT(&linkctl->zro_entry_name, "fcntl() lock attempt failed", errno);
 	linkctl->locked = TRUE;
 #	endif
 	return;
 }
 
+/* Routine same as relinkctl_lock_exclu() but instead UNLOCKs the lock */
 void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl)
 {
 	int	status;
 
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
+	assert(linkctl->locked);
+	if (!linkctl->locked)
+		return;
 	status = relinkctl_fcntl_lock(linkctl->fd, F_UNLCK);
-	assert(0 == status);	/* TODO: Deal with error */
+	if (-1 == status)
+		ISSUE_RELINKCTLERR_TEXT(&linkctl->zro_entry_name, "fcntl() unlock attempt failed", errno);
 	linkctl->locked = FALSE;
 #	endif
 	return;
@@ -327,7 +573,7 @@ void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl)
  *
  *   - status of fcntl() lock or unlock attempt
  */
-#ifdef USHBIN_SUPPORTED
+#ifdef AUTORELINK_SUPPORTED
 STATICFNDEF int relinkctl_fcntl_lock(int fd, int l_type)
 {
 	int		status;
@@ -345,124 +591,329 @@ STATICFNDEF int relinkctl_fcntl_lock(int fd, int l_type)
 }
 #endif
 
+#ifdef AUTORELINK_SUPPORTED
 /**
  * Relinkctl file record management routines
  */
 
-/* Like relinkctl_find_record, but inserts a new entry instead of returning REC_NOT_FOUND.
- */
-relinkrec_loc_t relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
+/* Like relinkctl_find_record, but inserts a new entry instead of returning NULL */
+relinkrec_t *relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
 {
-	relinkrec_loc_t		rec;
-	relinkrec_ptr_abs_t	base, newrec;
+	relinkrec_t	*base, *rec;
+	uint4		hash, prev_hash_index, nrec;
 
-#	ifdef USHBIN_SUPPORTED
-	rec = relinkctl_find_record(linkctl, rtnname);
-	if (REC_NOT_FOUND == rec)
-	{
+	COMPUTE_RELINKCTL_HASH(rtnname, hash);
+	rec = relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index);
+	if (NULL == rec)
+	{	/* Record not found while not under lock - lock it and try again */
 		relinkctl_lock_exclu(linkctl);
-		rec = relinkctl_find_record(linkctl, rtnname);
-		if (REC_NOT_FOUND == rec)
-		{	/* File expansion scenario - TODO - don't assume additional record is available */
+		rec = relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index);
+		if (NULL == rec)
+		{	/* Add a new record if room exists - else error */
 			assert(linkctl->locked);
-			assert(linkctl->n_records == linkctl->hdr->n_records);
+			nrec = linkctl->n_records;
+			assert(nrec == linkctl->hdr->n_records);	/* Assured by relinkctl_find_record() */
+			if (RELINKCTL_MAX_ENTRIES == linkctl->hdr->n_records)
+			{
+				relinkctl_unlock_exclu(linkctl);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RELINKCTLFULL, 3, linkctl->zro_entry_name.len,
+					      linkctl->zro_entry_name.addr, RELINKCTL_MAX_ENTRIES);
+			}
 			base = linkctl->rec_base;
-			newrec = base + (UINTPTR_T)linkctl->n_records;
-			newrec->cycle = 1;	/* Start at cycle 1 instead of 0 */
-			memset(&newrec->rtnname_fixed.c[0], 0, SIZEOF(mident_fixed));
+			rec = base + nrec;
+			memset(&rec->rtnname_fixed.c[0], 0, SIZEOF(mident_fixed));
 			assert(MAX_MIDENT_LEN >= rtnname->len);
-			memcpy(&newrec->rtnname_fixed.c[0], rtnname->addr, rtnname->len);
-			/* TODO: Insert record's AVL node into AVL tree or hash entry into htab */
+			/* assert(valid_mname(rtnname)) is not needed here because it was already done in relinkctl_find_record */
+			memcpy(&rec->rtnname_fixed.c[0], rtnname->addr, rtnname->len);
+			rec->cycle = 0;	/* Note incr_link() will bump this to 1 when routine is linked */
+			rec->hashindex_fl = 0;
+			rec->objhash = 0;
+			rec->rtnobj_shm_offset = (rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T;
+			if (prev_hash_index)
+			{
+				--prev_hash_index;
+				assert(prev_hash_index < nrec);
+				assert(0 == base[prev_hash_index].hashindex_fl);
+				base[prev_hash_index].hashindex_fl = nrec + 1;
+			} else
+				linkctl->shm_hashbase[hash] = nrec + 1;
 			linkctl->hdr->n_records++;
-			rec = RCTLABS2REL(newrec, base);
-			assert(rec == relinkctl_find_record(linkctl, rtnname));
+			assert(rec == relinkctl_find_record(linkctl, rtnname, hash, &prev_hash_index));
 		}
 		relinkctl_unlock_exclu(linkctl);
 	}
 	return rec;
-#	else
-	return 0;
-#	endif
 }
 
-/*
- * Iterate through each relink_record_struct starting at (relink_record_ptr)&linkctl->map_addr[0]
+/* Iterate through each relink_record_struct starting at (relink_record_ptr)&linkctl->map_addr[0]
  * Find rec s.t. rec->rtnname == rtnname, return offset of rec.
  * Otherwise, return NOMATCH (defined 0xffff..).
  */
-relinkrec_loc_t relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname)
+relinkrec_t *relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname, uint4 hash, uint4 *prev_hash_index)
 {
-	relinkrec_ptr_abs_t		rec, base, top;
-
-#	ifdef USHBIN_SUPPORTED
-	relinkctl_ensure_fullmap(linkctl);	/* Make sure we search among all currently existing records */
+	relinkrec_t		*rec, *base;
+	unsigned int		nrec, index;
+	sm_uint_ptr_t		ptr;
+	uint4			rtnhash, prev_index;
+
+	assert(valid_mname(rtnname));
+	linkctl->n_records = linkctl->hdr->n_records;	/* Make sure we search among all currently existing records */
+	ptr = linkctl->shm_hashbase;
+	assert(RELINKCTL_HASH_BUCKETS > hash);
+	ptr += hash;
+	prev_index = *ptr;
+	index = prev_index - 1;	/* 'index' is unsigned so will become huge positive number in case *ptr is 0 */
 	base = linkctl->rec_base;
-	top = base + (UINTPTR_T)linkctl->n_records;
-	for (rec = base; rec < top; rec++)
-	{	/* For each record, check routine name plus null trailer in fixed version */
+	nrec = linkctl->n_records;
+	assert(RELINKCTL_MAX_ENTRIES >= nrec);
+	while (index < nrec)
+	{
+		rec = &base[index];
+		DEBUG_ONLY(COMPUTE_RELINKCTL_HASH(rtnname, rtnhash);)
+		assert(rtnhash == hash);
+		/* Check routine name plus null trailer in fixed version */
 		if ((0 == memcmp(&rec->rtnname_fixed.c, rtnname->addr, rtnname->len))
-		    && ('\0' == rec->rtnname_fixed.c[rtnname->len]))
-			return RCTLABS2REL(rec, base);
+				&& ('\0' == rec->rtnname_fixed.c[rtnname->len]))
+			return rec;
+		assert(RELINKCTL_MAX_ENTRIES >= rec->hashindex_fl);
+		prev_index = index + 1;
+		index = rec->hashindex_fl - 1;
 	}
-#	endif
-	return REC_NOT_FOUND;
+	*prev_hash_index = prev_index;
+	return NULL;
 }
+#endif
 
 /**
  * Relinkctl file rundown routines
  */
 
 /*
- * Close all file descriptors associated with relinkctl structs, and (atomically) decrement nattached in file header.
+ * Unmap all relinkctl structs after (atomically) decrementing nattached field in relinkctl file header
  */
-void relinkctl_rundown(boolean_t decr_attached)
+void relinkctl_rundown(boolean_t decr_attached, boolean_t do_rtnobj_shm_free)
 {
-#	ifdef USHBIN_SUPPORTED
+#	ifdef AUTORELINK_SUPPORTED
 	int			rc;
-	open_relinkctl_sgm	*linkctl;
+	open_relinkctl_sgm	*linkctl, *nextctl;
+	rtn_tabent		*rtab;
+	rhdtyp			*rtnhdr;
+	relinkctl_data		*hdr;
+	int			shmid, i, nattached;
+	relinkshm_hdr_t		*shm_hdr;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	stack_frame		*fp;
+	boolean_t		is_mu_rndwn_rlnkctl, remove_shm;
+	struct shmid_ds		shm_buf;
+#	ifdef DEBUG
+	relinkrec_t		*linkrec, *linktop;
+	int			j, k;
+	rtnobj_sm_off_t		rtnobj_shm_offset;
+	boolean_t		clean_shutdown;
+#	endif
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+	if (do_rtnobj_shm_free && !TREF(gtm_autorelink_keeprtn))
 	{
+		assert(process_exiting);
+		/* Run through all loaded routines and if any are loaded in shared memory, decrement their reference counts.
+		 * Since this involves shared memory, this is best accomplished by invoking rtnobj_shm_free.
+		 * For non-shared objects, zr_unlink_rtn will only release process-private memory. Since this process is
+		 * going to die (asserted by process_exiting above) no need to do anything in that case.
+		 * But before that check if the M-stack has any frames with rtnhdr->rtn_relinked TRUE. These are
+		 * routine-header structures that are not added to the rtn_names[] array but could potentially have
+		 * done rtnobj_shm_malloc(). In that case do rtnobj_shm_free() on those to decrement shared memory refcnts.
+		 */
+		for (fp = frame_pointer; NULL != fp; fp = SKIP_BASE_FRAME(fp->old_frame_pointer))
+		{
+			rtnhdr = CURRENT_RHEAD_ADR(fp->rvector);
+			if ((NULL != rtnhdr) && rtnhdr->rtn_relinked && rtnhdr->shared_object)
+			{
+				rtnobj_shm_free(rtnhdr, LATCH_GRABBED_FALSE);
+				rtnhdr->rtn_relinked = FALSE;
+				rtnhdr->shared_object = FALSE;
+			}
+		}
+		for (rtab = rtn_names_end; rtab > rtn_names; rtab--, rtn_names_end = rtab)
+		{	/* [0] is not used (for some reason) */
+			rtnhdr = rtab->rt_adr;
+			if (rtnhdr->shared_object)
+				rtnobj_shm_free(rtnhdr, LATCH_GRABBED_FALSE);
+		}
+	}
+	is_mu_rndwn_rlnkctl = TREF(is_mu_rndwn_rlnkctl);
+	for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = nextctl)
+	{
+		for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+		{
+			if (NULL != linkctl->rtnobj_shm_base[i])
+			{
+				assert(INVALID_SHMID != linkctl->rtnobj_shmid[i]);
+				SHMDT(linkctl->rtnobj_shm_base[i]);
+				linkctl->rtnobj_shm_base[i] = NULL;
+			} else
+				assert(INVALID_SHMID == linkctl->rtnobj_shmid[i]);
+		}
 		if (decr_attached)
 		{
 			relinkctl_lock_exclu(linkctl);
-			linkctl->hdr->nattached--;
-			/*sprintf(buff, "%s - decremented. nattached = %d", linkctl->zro_entry_name, linkctl->hdr->nattached);
-			send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(buff));*/
-			/*send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
-	                                                        LEN_AND_STR(linkctl->zro_entry_name));
-	 		send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
-	                                                        LEN_AND_LIT("decremented")); debugging TODO */
-			relinkctl_unlock_exclu(linkctl);
-			assert(0 <= linkctl->hdr->nattached);
-			if (0 == linkctl->hdr->nattached)
+			hdr = linkctl->hdr;
+			assert(0 < hdr->nattached);
+			if (0 < hdr->nattached)
+				hdr->nattached--;
+			nattached = hdr->nattached;
+			DBGARLNK((stderr, "relinkctl_rundown : pid = %d : file %s : post-decr nattached = %d\n",
+				getpid(), linkctl->relinkctl_path, nattached));
+			assert(0 <= nattached);
+			assert(INVALID_SHMID != hdr->relinkctl_shmid);
+			shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+			if (0 == nattached)
+			{
+				DBGARLNK((stderr, "relinkctl_rundown : nattached = 0\n"));
+				remove_shm = TRUE;
+			} else if (is_mu_rndwn_rlnkctl)
+			{	/* If MUPIP RUNDOWN -RELINKCTL, check if shm_buff.nattch is 1 (i.e. mupip rundown -relinkctl
+				 * is the only one attached to this shm). If so, ignore nattached and run this shm down.
+				 * Most likely processees that had bumped nattached got kill -9ed.
+				 * If shm_buff.nattch is not 1, fix hdr->nattached to match shm_buf.nattch so when the time
+				 * comes for the last GTM process to rundown, it will remove the shm without the need for
+				 * any more MUPIP RUNDOWN -RELINKCTL commands.
+				 */
+				shmid = hdr->relinkctl_shmid;
+				if (0 != shmctl(shmid, IPC_STAT, &shm_buf))
+				{
+					assert(FALSE);
+					remove_shm = FALSE;
+				} else
+				{
+					nattached = shm_buf.shm_nattch - 1; /* remove self since we will do a SHMDT soon */
+					if (hdr->nattached != nattached)
+					{
+						hdr->nattached = nattached;	/* fix hdr->nattached while at this */
+						shm_hdr->rndwn_adjusted_nattch = TRUE;
+					}
+					remove_shm = !nattached;
+				}
+				if (!remove_shm)
+				{
+					assert(nattached);
+					gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLNKCTLRNDWNFL, 3,
+								RTS_ERROR_MSTR(&linkctl->zro_entry_name), nattached);
+				}
+			} else
+				remove_shm = FALSE;
+			if (remove_shm)
+			{
+#				ifdef DEBUG
+				clean_shutdown = (!shm_hdr->rndwn_adjusted_nattch && !shm_hdr->skip_rundown_check);
+				if (clean_shutdown)
+				{
+					/* Check that ALL reference counts are zero */
+					for (linkrec = linkctl->rec_base, linktop = &linkrec[hdr->n_records];
+						linkrec < linktop; linkrec++)
+					{
+						assert(grab_latch(&linkrec->rtnobj_latch, 0));	/* 0 => do not wait for latch */
+						DEBUG_ONLY(rtnobj_shm_offset = linkrec->rtnobj_shm_offset;)
+						assert(NULL_RTNOBJ_SM_OFF_T == rtnobj_shm_offset);
+						assert(0 == linkrec->objLen);
+						assert(0 == linkrec->usedLen);
+					}
+					grab_latch(&shm_hdr->relinkctl_latch, 0);	/* 0 => do not wait for latch */
+				}
+				/* No need to release latch as we will be deleting the shared memory anyways */
+#				endif
+				for (i = 0; i < NUM_RTNOBJ_SHM_INDEX; i++)
+				{
+					rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[i];
+					assert(!clean_shutdown || (0 == rtnobj_shm_hdr->real_len));
+					assert(!clean_shutdown || (0 == rtnobj_shm_hdr->used_len));
+					shmid = rtnobj_shm_hdr->rtnobj_shmid;
+					if (INVALID_SHMID != shmid)
+					{
+#						ifdef DEBUG
+						if (clean_shutdown)
+						{	/* Note: shmctl can fail if some other process changes permissions
+							 * concurrently (after we had attached to the shmid) so account for
+							 * that in the assert below.
+							 */
+							if (0 == shmctl(shmid, IPC_STAT, &shm_buf))
+							{
+							/* We expect no one else to be attached to relinkctl shm. One case we
+							 * know of is if a process opens a PIPE device and iopi_open forks off
+							 * a child (which would cause shm_nattch to increment implicitly) and
+							 * continues execution issuing say a CRYPTNOSEEK error and exit BEFORE the
+							 * child process has done the EXEC (which would cause the shm_nattch to
+							 * decrement it back to the expected value). Account for it in the assert.
+							 */
+								assert((0 == shm_buf.shm_nattch) || TREF(fork_without_child_wait));
+							}
+							k = i + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS;
+							assert(rtnobj_shm_hdr->shm_len
+								== ((gtm_uint64_t)1 << (k + MIN_RTNOBJ_SIZE_BITS)));
+							for (j = 0; j < NUM_RTNOBJ_SIZE_BITS; j++)
+							{
+								if (j != k)
+								{
+									assert(NULL_RTNOBJ_SM_OFF_T
+										== rtnobj_shm_hdr->freeList[j].fl);
+									assert(NULL_RTNOBJ_SM_OFF_T
+										== rtnobj_shm_hdr->freeList[j].bl);
+								} else
+								{
+									assert(OFFSETOF(rtnobj_hdr_t, userStorage)
+											== rtnobj_shm_hdr->freeList[j].fl);
+									assert(OFFSETOF(rtnobj_hdr_t, userStorage)
+										== rtnobj_shm_hdr->freeList[j].bl);
+								}
+							}
+						}
+#						endif
+						shm_rmid(shmid); /* If error removing shmid, not much we can do. Just move on */
+					}
+				}
+				SHMDT(shm_hdr);		/* If error detaching, not much we can do. Just move on */
+				shmid = hdr->relinkctl_shmid;
+				shm_rmid(shmid);	/* If error removing shmid, not much we can do. Just move on */
+				relinkctl_delete(linkctl);
+				if (is_mu_rndwn_rlnkctl)
+					gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RLNKCTLRNDWNSUC, 2,
+								RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+			} else
 			{
-				relinkctl_lock_exclu(linkctl);
-				if (0 == linkctl->hdr->nattached)
-					relinkctl_delete(linkctl);
+				SHMDT(shm_hdr);		/* If error detaching, not much we can do. Just move on */
 			}
+			linkctl->rec_base = NULL;
+			linkctl->shm_hashbase = NULL;
+			relinkctl_unlock_exclu(linkctl);
 		}
-		CLOSEFILE_RESET(linkctl->fd, rc);
-		linkctl->hdr = NULL;
-		linkctl->rec_base = NULL;
+		relinkctl_unmap(linkctl);	/* sets "linkctl->hdr" to NULL */
+		nextctl = linkctl->next;
+		free(linkctl);
 	}
 	TREF(open_relinkctl_list) = NULL;
 #	endif
 	return;
 }
 
+#ifdef AUTORELINK_SUPPORTED
 /*
- * Clean up (i.e. delete) relinkctl file
+ * Clean up (i.e. delete) relinkctl file whose descriptor block is passed in
  */
-#ifdef USHBIN_SUPPORTED
 STATICFNDEF void relinkctl_delete(open_relinkctl_sgm *linkctl)
 {
-	char	relinkctl_path[GTM_PATH_MAX + 1];
+	int	status;
 
-	relinkctl_get_key(relinkctl_path, &linkctl->zro_entry_name);
-	UNLINK(relinkctl_path);
+	DBGARLNK((stderr, "relinkctl_delete : pid = %d : Deleting %s\n", getpid(), linkctl->relinkctl_path));
+	status = UNLINK(linkctl->relinkctl_path);
+	/* If unlink succeeds, then set "hdr->file_deleted" to TRUE to notify other processes in relinkctl_open
+	 * about this concurrent delete so they can reattach. If the unlink fails (e.g. due to permission issues)
+	 * do not set "hdr->file_deleted".
+	 */
+	if (-1 != status)
+		linkctl->hdr->file_deleted = TRUE; /* Notify any other process in relinkctl_open about this so they can reattach */
+	else
+		linkctl->hdr->initialized = FALSE;	/* So next process reinitializes hdr->relinkctl_shmid etc. */
 	return;
 }
 #endif
diff --git a/sr_unix/relinkctl.h b/sr_unix/relinkctl.h
index 8879242..84a1bf0 100644
--- a/sr_unix/relinkctl.h
+++ b/sr_unix/relinkctl.h
@@ -12,52 +12,148 @@
 #ifndef RELINKCTL_H_INCLUDED
 #define RELINKCTL_H_INCLUDED
 
+# include "gtm_limits.h"
 
-/* For autorelink debugging, uncomment the line below */
-/* #define AUTORELINK_DEBUG */
-#if defined(AUTORELINK_DEBUG)
-# define DBGARLNK(x) DBGFPF(x)
-# define DBGARLNK_ONLY(x) x
-# include "gtm_stdio.h"
-# include "gtmio.h"
+/* Input RTNNAME is derived from an object file name and we need to convert it to a proper routine name.
+ * a) It is possible we got a '_' as the first character in case of a % routine. But the actual routine name stored in
+ *	that object file would have '%' as the first character. Fix that.
+ * b) Also limit routine name length to MAX_MIDENT_LEN (internal design max). Ignore the rest of the file name.
+ */
+#define	CONVERT_FILENAME_TO_RTNNAME(RTNNAME)		\
+{							\
+	if ('_' == RTNNAME.addr[0])			\
+		RTNNAME.addr[0] = '%';			\
+	if (MAX_MIDENT_LEN < RTNNAME.len)		\
+		RTNNAME.len = MAX_MIDENT_LEN;		\
+}
+
+#define	COMPUTE_RELINKCTL_HASH(RTNNAME, RTNHASH)		\
+{								\
+	STR_HASH((RTNNAME)->addr, (RTNNAME)->len, RTNHASH, 0);	\
+	RTNHASH = RTNHASH % RELINKCTL_HASH_BUCKETS;		\
+}
+
+/* One relinkctl file can contain at most this many # of routines */
+#ifdef DEBUG
+#  define	RELINKCTL_MAX_ENTRIES	(WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 100 : 1000000)
+#else
+#  define	RELINKCTL_MAX_ENTRIES	1000000
+#endif
+
+/* The first prime # above RELINKCTL_MAX_ENTRIES */
+#ifdef DEBUG
+#  define	RELINKCTL_HASH_BUCKETS	(WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 101 : 1000003)
 #else
-# define DBGARLNK(x)
-# define DBGARLNK_ONLY(x)
+#  define	RELINKCTL_HASH_BUCKETS	1000003
 #endif
 
-#define	MIN_RELINKCTL_MAPSZ	1024 /* bytes */
-#define REC_NOT_FOUND 		(relinkrec_loc_t)(-1)
+#define	RELINKCTL_MMAP_SZ	((size_t)SIZEOF(relinkctl_data))
+#define	RELINKSHM_HDR_SIZE	((size_t)SIZEOF(relinkshm_hdr_t))
+/* We are guaranteed RELINKCTL_HASH_BUCKETS is an odd prime number and since we want at least 8-byte alignment between different
+ * sections of shared memory, we add a 4-byte filler to the RELINKSHM_RTNHASH_SIZE macro computation.
+ */
+#define	RELINKSHM_RTNHASH_SIZE	(((size_t)RELINKCTL_HASH_BUCKETS + 1) * SIZEOF(uint4))	/* see above comment for why "+ 1" */
+#define	RELINKSHM_RECARRAY_SIZE	((size_t)RELINKCTL_MAX_ENTRIES * SIZEOF(relinkrec_t))
+#define	RELINKCTL_SHM_SIZE	(RELINKSHM_HDR_SIZE + RELINKSHM_RTNHASH_SIZE + RELINKSHM_RECARRAY_SIZE)
 
-/* Macros for dealing with relative and absolute addresses and converting between them */
-#define RCTLABS2REL(ABSADR, BASEADR) ((relinkrec_loc_t)((UINTPTR_T)(ABSADR) - (UINTPTR_T)(BASEADR)))
-#define RCTLREL2ABS(RELADR, BASEADR) ((relinkrec_ptr_abs_t)((UINTPTR_T)(BASEADR) + (UINTPTR_T)(RELADR)))
+#define	GET_RELINK_SHM_HDR(LINKCTL)	(relinkshm_hdr_t *)((sm_uc_ptr_t)LINKCTL->shm_hashbase - SIZEOF(relinkshm_hdr_t))
 
-/* Macro to read the cycle# of a given relinkctl record */
-#define RELINKCTL_CYCLE_READ(LINKCTL, RECOFFSET) (((relinkrec_ptr_abs_t)(RCTLREL2ABS((RECOFFSET), (LINKCTL)->rec_base)))->cycle)
-/* Macro to bump the cycle# of a given relinkctl record */
-#define RELINKCTL_CYCLE_INCR(LINKCTL, RECOFFSET) (((relinkrec_ptr_abs_t)(RCTLREL2ABS((RECOFFSET), (LINKCTL)->rec_base)))->cycle++)
+error_def(ERR_RLNKRECLATCH);	/* needed for the RELINKCTL_CYCLE_INCR macro */
 
-/*
- * Possible TODO as it relates to ensuring consistent code state:
- * 	Along with cycle and rtnname, put MD5 checksum in record. When a process ZLINKs, ensure that checksum of object matches?
- * 	something like:
- * 	1. open() object file, note rhdr->MD5
- * 	2. Note rec->MD5
- * 	3. Issue error if different (unless it's different because of concurrent ZRUPDATE, in which case repeat from step 1.)
+/* Macro to bump the cycle# of a given relinkctl record. Make sure shared cycle never becomes 0 after the bump since a process
+ * initializes its private cycle to 0 at relinkctl file open time and we want to make sure the private-cycle == shared-cycle
+ * check fails always the first time for a process.
+ */
+#define RELINKCTL_CYCLE_INCR(RELINKREC, LINKCTL)						\
+{												\
+	if (!grab_latch(&(RELINKREC)->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC))			\
+	{											\
+		assert(FALSE);									\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLNKRECLATCH, 3,			\
+			RELINKREC->rtnname_fixed.c, RTS_ERROR_MSTR(&LINKCTL->zro_entry_name));	\
+	}											\
+	if (0 == ++(RELINKREC)->cycle)								\
+		++(RELINKREC)->cycle;								\
+	rel_latch(&(RELINKREC)->rtnobj_latch);							\
+}
+
+/* A routine buffer is stored a shared memory segment. Since shm sizes are fixed, if ever we cannot fit in a given routine
+ * buffer in a given shm, we create another shm with double the size and keep doing this until we come with a shm that can
+ * fit in the given routine buffer. We allow for a max of MAX_RTNOBJ_SHM_INDEX such shmids to be allocated per relinkctl file.
+ * Since we need 6 bits to represent MAX_RTNOBJ_SHM_INDEX, we treat the array of shmids to be on huge 2**64 sized shmid. Where
+ * the top 6 bits represent the index in the shmid array and the remaining 58 bits correspond to the offset within that shmid
+ * where the routine buffer can be found. Such an offset into a routine buffer in shared memory is typed as rtnobj_sm_off_t.
  */
+#define	RTNOBJ_SHMID_INDEX_MAXBITS	6	/* Max # of bits needed to store NUM_RTNOBJ_SHM_INDEX */
+#define	MIN_RTNOBJ_SHM_INDEX	20	/* Minimum size of shared memory segment created to store .o (rtnobj) files is 2**20.
+					 * Do not change this macro as gtm_autorelink_shm env var is specified in a multiple of
+					 * 2**MIN_RTNOBJ_SHM_INDEX bytes and will have user doc implications.
+					 */
+#define	MAX_RTNOBJ_SHM_INDEX	58	/* Maximum size of shared memory segment created to store .o (rtnobj) files is 2**57 */
+#define NUM_RTNOBJ_SHM_INDEX	(MAX_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SHM_INDEX)
+
+#define	NULL_RTNOBJ_SM_OFF_T	((sm_off_t)MAXUINT8)	/* Is (2**64 - 1) i.e. 0xFFFF FFFF FFFF FFFF */
+
+#define	RTNOBJ_GET_SHM_INDEX(SHM_OFF)	(SHM_OFF >> MAX_RTNOBJ_SHM_INDEX)
+#define	RTNOBJ_GET_SHM_OFFSET(SHM_OFF)	(SHM_OFF & 0x03FFFFFFFFFFFFFFULL)
+#define	RTNOBJ_SET_SHM_INDEX_OFF(SHM_INDEX, SHM_OFF)	(((rtnobj_sm_off_t)SHM_INDEX << MAX_RTNOBJ_SHM_INDEX) | (SHM_OFF))
+
+#define	RLNKSHM_LATCH_TIMEOUT_SEC	60	/* Want to wait 60 seconds max */
+#define	RLNKREC_LATCH_TIMEOUT_SEC	60	/* Want to wait 60 seconds max */
+
+#define	MIN_RTNOBJ_SIZE_BITS	8		      /* Minimum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**8 = 256 */
+#define	MAX_RTNOBJ_SIZE_BITS	MAX_RTNOBJ_SHM_INDEX  /* Maximum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**32
+						       * but when we allocate a rtnobj shared memory segment of size
+						       * (2**MAX_RTNOBJ_SHM_INDEX) we want to add that as one element to the
+						       * "rtnobjshm_hdr_t->freeList[]" array and hence this definition.
+						       */
+#define	NUM_RTNOBJ_SIZE_BITS	(MAX_RTNOBJ_SIZE_BITS + 1 - MIN_RTNOBJ_SIZE_BITS)
 
-/* Shared structure - relink record in a relinkctl (mmap'd) file */
+#define	IS_INSERT		0
+#define	IS_DELETE		1
+
+#define ISSUE_RELINKCTLERR_SYSCALL(ZRO_ENTRY_NAME, ERRSTR, ERRNO)						\
+	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME),		\
+		      ERR_SYSCALL, 5, LEN_AND_STR(ERRSTR), CALLFROM, DEBUG_ONLY(saved_errno = )ERRNO)
+
+#define ISSUE_RELINKCTLERR_TEXT(ZRO_ENTRY_NAME, ERRORTEXT, ERRNO)						\
+	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME),		\
+		      ERR_TEXT, 2, LEN_AND_STR(ERRORTEXT), DEBUG_ONLY(saved_errno = )ERRNO)
+
+typedef	gtm_uint64_t	rtnobj_sm_off_t;
+
+/* Shared structure - relink record corresponding to a relinkctl file (resides in shared memory) */
 typedef struct relinkrec_struct
 {
 	mident_fixed	rtnname_fixed;
 	uint4		cycle;
-	/* TODO: Add hash or tree or sorted list lookup for speed */
+	uint4		hashindex_fl;	/* Forward link ptr to linked list of relinkrec_t structures that have same rtnhash value */
+	uint4		numvers;		/* Number of versions of this .o file currently in this relinkctl shared memory */
+	uint4		filler_8byte_align;
+	gtm_uint64_t	objLen;			/* Total object file length of various versions of this .o file in shared memory */
+	gtm_uint64_t	usedLen;		/* Total length used up in shared memory for various versions of this .o file.
+						 * Due to rounding up of objLen to nearest 2-power, usedLen >= objLen always.
+						 */
+	rtnobj_sm_off_t	rtnobj_shm_offset;	/* offset into shared memory where this object file can be found for linking.
+						 * If object is not loaded, set to NULL_RTNOBJ_SM_OFF_T.
+						 */
+	global_latch_t	rtnobj_latch;	/* Lock used to search/insert/delete entries in the
+					 * object file linked list (starting at rtnobj_shm_offset)
+					 */
+	gtm_uint64_t	objhash;	/* Hash of the object file last touched here */
+	CACHELINE_PAD_COND(88, 1)	/* Add 40 bytes (on top of 88 bytes) to make this structure 128 bytes to avoid cacheline
+					 * interference (between successive relinkrec_t structures in shared memory) on the RS6000
+					 * (where the cacheline is 128 bytes currently). Other platforms have smaller
+					 * cachelines (i.e. 64 bytes or lesser) and so this structure (88 bytes currently)
+					 * taking up more than one cacheline dont require this padding.
+					 */
 } relinkrec_t;
 
+#define	ZRO_DIR_PATH_MAX	255
+
 /* Shared structure - relinkctl file header */
 typedef struct relinkctl_data_struct
 {
-	/* TODO: Add zro_entry_name, so that we can "rundown" or delete desired structs */
 	uint4		n_records;
 	int4		nattached;	/* Number of processes currently attached. this is approximate, because if a process
 					 * is kill 9'd, nattached is not decrememented.
@@ -66,36 +162,140 @@ typedef struct relinkctl_data_struct
 					 * 	1. SYSV semaphore (as with the db). increment in open_relinkctl
 					 * 	2. When we want to cleanup (say mupip routine -rundown), execute 'fuser'
 					 */
-	global_latch_t	attach_latch;
-	relinkrec_t	base[1];
+	int4		relinkctl_shmid;/* ID of primary shared memory segment corresponding to the mmaped relinkctl file.
+					 * This contains the array of relinkrec_t structures as well as hash buckets to
+					 * speed up search of routine names.
+					 */
+	uint4		relinkctl_shmlen;/* size of shared memory */
+	int4		file_deleted;	/* Way of signaling processes in relinkctl_open about a concurrent delete so they
+					 * close their fd and reopen the file.
+					 */
+	uint4		initialized;	/* relinkctl file has been successfully initialized */
+	char		zro_entry_name[ZRO_DIR_PATH_MAX + 1];	/* null-terminated full path of the directory in $zroutines
+								 * whose relinkctl file is this. Given a relinkctl file, one can
+								 * use this to find the corresponding directory.
+								 */
+	int		zro_entry_name_len;	/* strlen of the null-terminated "zro_entry_name" */
 } relinkctl_data;
 
-typedef off_t			relinkrec_ptr_rel_t;	/* Relative offset of relinkrec */
-typedef relinkrec_t		*relinkrec_ptr_abs_t;	/* Absolute pointer to relinkrec */
-/* For now at least, use relative pointers as primary way of referring to shared relink records */
-typedef relinkrec_ptr_rel_t	relinkrec_loc_t;
-
 /* Process private structure - describes a relinkctl file. Process private so can be linked into a list in $ZROUTINES order */
 typedef struct open_relinkctl_struct
 {
 	struct open_relinkctl_struct	*next;			/* List of open ctl structures, sorted by zro_entry_name */
-	mstr				zro_entry_name;		/* Text resident in stringpool */
-	int				fd;
+	mstr				zro_entry_name;		/* object directory name from $zroutines */
+	char				*relinkctl_path;	/* full path of the relinkctl file corresponding to this objdir */
 	uint4				n_records;		/* Private copy */
+	boolean_t			locked;			/* TRUE if this process owns exclusive lock */
 	relinkctl_data			*hdr;			/* Base of mapped file */
 	relinkrec_t			*rec_base;
-	boolean_t			locked;			/* TRUE if this process owns exclusive lock */
+	sm_uint_ptr_t			shm_hashbase;		/* base of hash table in shared memory */
+	sm_uc_ptr_t			rtnobj_shm_base[NUM_RTNOBJ_SHM_INDEX];
+	int				rtnobj_shmid[NUM_RTNOBJ_SHM_INDEX];
+	int				fd;
+	int				rtnobj_shmid_cycle;	/* copied over from relinkshm_hdr->shmid_cycle after
+								 * ensuring all relinkshm_hdr->shmid[NUM_RTNOBJ_SHM_INDEX] is
+								 * copied over and all those shmids have been successfully
+								 * shmat()ed.
+								 */
+	int				rtnobj_min_shm_index;	/* Copied over from relinkshm_hdr->rtnobj_min_shm_index */
+	int				rtnobj_max_shm_index;	/* Copied over from relinkshm_hdr->rtnobj_max_shm_index */
 } open_relinkctl_sgm;
 
+typedef struct rtnobjshm_hdr_struct
+{
+	que_ent		freeList[NUM_RTNOBJ_SIZE_BITS];
+	int		rtnobj_min_free_index;	/* minimum 'i' where freeList[i] has non-zero fl,bl links */
+	int		rtnobj_max_free_index;	/* maximum 'i' where freeList[i-1] has non-zero fl,bl links
+						 * if no freeList[i] has non-zero fl,bl links, this will be set to  0.
+						 */
+	int		rtnobj_shmid;
+	gtm_uint64_t	real_len;	/* sum of realLen of .o files used currently in this rtnobj shared memory segment */
+	gtm_uint64_t	used_len;	/* sum of space occupied by .o files currently in this rtnobj shared memory segment */
+	gtm_uint64_t	shm_len;	/* size of shared memory segment */
+} rtnobjshm_hdr_t;
+
+/* Shared memory header structure corresponding to relinkctl file. This is followed by a hash-array for speedy routine name
+ * access.
+ */
+typedef struct relinkshm_hdr
+{
+	char		relinkctl_fname[GTM_PATH_MAX];	/* full path of the relinkctl file (mmr hash is in this name) */
+	int		min_shm_index;
+	int		rtnobj_min_shm_index;		/* Minimum 'i' where rtnobj_shmhdr[i].rtnobj_shmid is a valid shmid */
+	int		rtnobj_max_shm_index;		/* Maximum 'i' where rtnobj_shmhdr[i-1].rtnobj_shmid is a valid shmid.
+							 * If no rtnobj_shmhdr[i] has valid shmid, this will be set to 0.
+							 */
+	int		rtnobj_shmid_cycle;		/* bumped when rtnobj_shmhdr[i].rtnobj_shmid gets created for some 'i' */
+	boolean_t	rndwn_adjusted_nattch;		/* MUPIP RUNDOWN -RELINKCTL did adjust nattached */
+#	ifdef DEBUG
+	boolean_t	skip_rundown_check;		/* TRUE if at least one process with gtm_autorelink_keeprtn=1 opened this */
+#	endif
+	rtnobjshm_hdr_t	rtnobj_shmhdr[NUM_RTNOBJ_SHM_INDEX];
+	/* CACHELINE_PAD macro usages surrounding the actual latch below provides spacing so updates to the latch do not interfere
+	 * with updates to adjoining fields which can happen if they fall in the same data cacheline of a processor. No
+	 * CACHELINE_PAD before the latch as adjoining fields before the latch are updated only if we hold the latch so no
+	 * interference possible.
+	 */
+	global_latch_t	relinkctl_latch;	/* latch for insertions/deletions of buddy list structurs in any rtnobj shmids */
+	CACHELINE_PAD(SIZEOF(global_latch_t), 1)
+} relinkshm_hdr_t;
+
+#define	STATE_FREE	0
+#define	STATE_ALLOCATED	1
+
+/* "refcnt" is a signed 4-byte integer so the max it can go to is 2**31-1.
+ * Once it reaches this value, we can no longer accurately maintain refcnt (rollover issues).
+ * So keep it there thereby never removing the corresponding object from shared memory.
+ */
+#define	REFCNT_INACCURATE	MAXPOSINT4
+
+/* Header structure for each .o file in the "rtnobj" shared memory */
+typedef struct rtnobj_hdr_struct
+{
+	unsigned short	queueIndex;			/* 2**queueIndex is the size of this element (including this header) */
+	unsigned char	state;				/* State of this block */
+	unsigned char	initialized;			/* Has the .o file been read from disk into this slot */
+	int4		refcnt;				/* # of processes that are currently using this .o file */
+	gtm_uint64_t	objhash;			/* 8-byte checksum of object file contents.
+							 * Used to differentiate multiple versions of the .o file with the same
+							 * routine name; Each gets a different routine buffer in shared memory.
+							 */
+	rtnobj_sm_off_t	next_rtnobj_shm_offset;		/* Offset into shared memory where the routine buffer of the .o file with
+							 * the same name as this one can be found but with a different checksum.
+							 * Basically a linked list. Null pointer set to NULL_RTNOBJ_SM_OFF_T.
+							 */
+	uint4		relinkctl_index;		/* Index into reclinkrec_t[] array where the rtnname corresponding to this
+							 * .o file can be found; Note multiple versions of .o file with different
+							 * <src_cksum_8byte,objLen> values will have different routine buffers in
+							 * shared memory each of them pointing back to the same relinkctl_index.
+							 */
+	uint4		objLen;				/* Size of the allocated .o file. Currently not allowed to go > 4Gb.
+							 * <src_cksum_8byte,objLen> together are used to differentiate multiple
+							 * versions of the same .o file name; Each of them with a different value
+							 * of either src_cksum_8byte or objLen gets a different routine buffer in
+							 * shared memory. Note that it is theoretically possible (though rare) that
+							 * two different .o files have the same 8-byte src checksum and same objLen.
+							 * In that case they will use the same routine buffer. But since we expect
+							 * this to be very rare in practice, we consider this acceptable for now.
+							 */
+	union
+	{
+		que_ent		freePtr;		/* Pointer to next and previous storage element on free queue */
+		unsigned char	userStart;		/* First byte of user useable storage */
+	} userStorage;
+} rtnobj_hdr_t;
+
 /*
  * Prototypes
  */
 open_relinkctl_sgm *relinkctl_attach(mstr *obj_container_name);
-relinkrec_loc_t relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
-relinkrec_loc_t relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
+void	relinkctl_incr_nattached(void);
+int relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name);
+relinkrec_t *relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname, uint4 hash, uint4 *prev_hash_index);
+relinkrec_t *relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
 void relinkctl_open(open_relinkctl_sgm *linkctl);
-void relinkctl_ensure_fullmap(open_relinkctl_sgm *linkctl);
 void relinkctl_lock_exclu(open_relinkctl_sgm *linkctl);
 void relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl);
-void relinkctl_rundown(boolean_t decr_attached);
+void relinkctl_rundown(boolean_t decr_attached, boolean_t do_rtnobj_shm_free);
+
 #endif /* RELINKCTL_H_INCLUDED */
diff --git a/sr_unix/repl_inst_dump.c b/sr_unix/repl_inst_dump.c
index 94e7e63..9a5461c 100644
--- a/sr_unix/repl_inst_dump.c
+++ b/sr_unix/repl_inst_dump.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2006, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2006, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -821,6 +821,10 @@ void	repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr)
 				string, gtmsourcelocal_ptr->read_state);
 		}
 
+		PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, jnlfileonly), SIZEOF(gtmsourcelocal_ptr->jnlfileonly));
+		PRINT_BOOLEAN(PREFIX_SOURCELOCAL "Journal File Only                   !R12AZ",
+				gtmsourcelocal_ptr->jnlfileonly, idx);
+
 		PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, read), SIZEOF(gtmsourcelocal_ptr->read));
 		util_out_print( PREFIX_SOURCELOCAL "Relative Read Offset                  !10UL [0x!XL]", TRUE, idx,
 			gtmsourcelocal_ptr->read, gtmsourcelocal_ptr->read);
diff --git a/sr_unix/repl_msg.h b/sr_unix/repl_msg.h
index 5ade5bf..5eb67b8 100644
--- a/sr_unix/repl_msg.h
+++ b/sr_unix/repl_msg.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2006, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2006, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -66,10 +66,11 @@ enum
 #define	REPL_PROTO_VER_MULTISITE_CMP	(char)0x2	/* Versions V5.3-003 and above that support multisite replication with
 							 * the ability to compress the logical records in the replication pipe.
 							 */
-#define	REPL_PROTO_VER_SUPPLEMENTARY	(char)0x3	/* Versions V5.5-000 and above that support supplementary instances */
-#define	REPL_PROTO_VER_REMOTE_LOGPATH	(char)0x4	/* Versions V6.0-003 and above that send remote $CWD as part of handshake */
-#define REPL_PROTO_VER_TLS_SUPPORT	(char)0x5	/* Versions V6.1-000 and above that supports SSL/TLS communication. */
-#define	REPL_PROTO_VER_THIS		REPL_PROTO_VER_TLS_SUPPORT
+#define	REPL_PROTO_VER_SUPPLEMENTARY	(char)0x3	/* Versions >= V5.5-000 that support supplementary instances */
+#define	REPL_PROTO_VER_REMOTE_LOGPATH	(char)0x4	/* Versions >= V6.0-003 that send remote $CWD as part of handshake */
+#define REPL_PROTO_VER_TLS_SUPPORT	(char)0x5	/* Versions >= V6.1-000 that supports SSL/TLS communication. */
+#define REPL_PROTO_VER_XENDIANFIXES	(char)0x6	/* Versions >= V6.2-001 support cross-endian replication (GTM-8205) */
+#define	REPL_PROTO_VER_THIS		REPL_PROTO_VER_XENDIANFIXES
 							/* The current/latest version of the communication protocol between the
 							 * primary (source server) and secondary (receiver server or rollback)
 							 */
@@ -225,7 +226,8 @@ typedef struct	/* used to send a message of type REPL_NEED_INSTINFO */
 					 * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */
 	char		is_rootprimary;	/* Whether the source server that is sending this message is a root primary or not. */
 	char		is_supplementary;	/* TRUE for a supplementary instance; FALSE otherwise */
-	char		filler_32[5];
+	char		jnl_ver;	/* jnl format of this side */
+	char		filler_32[4];
 } repl_needinst_msg_t; /* The first two fields should be as in repl_msg_t */
 
 typedef struct	/* used to send a message of type REPL_OLD_INSTANCE_INFO */
diff --git a/sr_unix/rtnhdr.h b/sr_unix/rtnhdr.h
index aa173fb..8b0ac0d 100644
--- a/sr_unix/rtnhdr.h
+++ b/sr_unix/rtnhdr.h
@@ -52,6 +52,35 @@ typedef struct
 	char_ptr_t	ext_ref;	/* Address (quadword on alpha) this linkage entry resolves to or NULL */
 } lnk_tabent;
 
+#ifdef AUTORELINK_SUPPORTED
+#include "relinkctl.h"		/* Needed for open_relinkctl_sgm type in zro_validation_entry */
+/* Link search history entry - contains information to find the record in the relevant relinkctl file and what
+ * the cycle was when loaded.
+ */
+typedef struct
+{
+	uint4			cycle;			/* Copy of relinkctl file cycle when loaded */
+	relinkrec_t		*relinkrec;		/* Pointer to relinkctl record */
+	open_relinkctl_sgm	*relinkctl_bkptr;	/* Address of mapped relinkctl file */
+} zro_validation_entry;
+/* Header for search history block */
+typedef struct
+{
+	uint4			zroutines_cycle;	/* Value of set_zroutines_cycle when history created */
+	zro_validation_entry	*end;			/* -> Last record + 1 */
+	zro_validation_entry	base[1];		/* First history record (others follow) */
+} zro_hist;
+/* Structure used to queue up a list of validation entries and routine names before finalizing them into a
+ * zro_hist structure.
+ */
+typedef struct
+{
+	zro_validation_entry	zro_valent;		/* Validation entry data (this record) */
+	mident_fixed		rtnname;		/* Routine name associated with this validation entry */
+	int4			rtnname_len;
+} zro_search_hist_ent;
+#endif
+
 /* rhead_struct is the routine header; it occurs at the beginning of the
  * object code part of each module. Since this structure may be resident in
  * a shared library, this structure is considered inviolate. Therefore there is
@@ -87,12 +116,15 @@ typedef struct	rhead_struct
 	int4			lnrtab_len;		/* Number of linenumber table entries */
 	unsigned char		*literal_text_adr;	/* Address of literal text pool (offset in original rtnhdr) */
 	int4			literal_text_len;	/* Length of literal text pool */
+	boolean_t		shared_object;		/* Linked as a shared object */
 	mval			*literal_adr;		/* (#) Address of literal mvals (offset in original rtnhdr) */
 	int4			literal_len;		/* Number of literal mvals */
 	lnk_tabent		*linkage_adr;		/* (#) Address of linkage Psect (offset in original rtnhdr) */
 	int4			linkage_len;		/* Number of linkage entries */
 	int4			rel_table_off;		/* Offset to relocation table (not kept) */
 	int4			sym_table_off;		/* Offset to symbol table (not kept) */
+	boolean_t		rtn_relinked;		/* Routine has been relinked while this version was active. Check on
+							 * unwind to see if this routine needs to be cleaned up. */
 	unsigned char		*shared_ptext_adr;	/* If shared routine (shared library or object), points to shared copy */
 	unsigned char		*ptext_adr;		/* (#) address of start of instructions (offset in original rtnhdr)
 							 * If shared routine, points to shared copy unless breakpoints are active.
@@ -102,6 +134,7 @@ typedef struct	rhead_struct
 	int4			checksum;		/* 4-byte source code checksum (for platforms where MD5 is unavailable) */
 	int4			temp_mvals;		/* (#) temp_mvals value of current module version */
 	int4			temp_size;		/* (#) temp_size value of current module version */
+	boolean_t		has_ZBREAK;		/* This routine has a ZBREAK in it - disable it for autorelink */
 	struct rhead_struct	*current_rhead_adr;	/* (#) Address of routine header of current module version */
 	struct rhead_struct	*old_rhead_adr;		/* (#) Chain of replaced routine headers */
 #	ifdef GTM_TRIGGER
@@ -109,14 +142,18 @@ typedef struct	rhead_struct
 #	else
 	void_ptr_t		filler1;
 #	endif
-	unsigned char		checksum_md5[16];	/* 16-byte MD5 checksum of routine source code */
+	unsigned char		checksum_128[16];	/* 16-byte MurmurHash3 checksum of routine source code */
 	struct rhead_struct	*active_rhead_adr;	/* Chain of active old versions, fully reserved for continued use */
 	routine_source		*source_code;		/* Source code used by $TEXT */
-	void_ptr_t		zhist;			/* If shared object -> validation list/array (actual type is zro_hist *) */
+	ARLINK_ONLY(zro_hist	*zhist;)		/* If shared object -> validation list/array */
+	gtm_uint64_t		objhash;		/* When object file is created, contains hash of object file */
 	unsigned char		*lbltext_ptr;		/* Label name text blob if shared object replaced */
-	uint4			shared_len;		/* Length of mmaped segment (needed for munmap) */
+	uint4			object_len;		/* Length of wrapped GT.M object */
 	uint4			routine_source_offset;	/* Offset of M source within literal text pool */
-	IA64_ONLY(void_ptr_t	filler2;)		/* IA64 needs 16 byte alignment */
+	mstr			*linkage_names;		/* Offset to mstr table of symbol names indexed same as linkage table */
+#	ifdef AUTORELINK_SUPPORTED
+	open_relinkctl_sgm	*relinkctl_bkptr;	/* Back pointer to relinkctl file that loaded this shared rtnobj */
+#	endif
 } rhdtyp;
 
 /* Routine table entry */
@@ -178,6 +215,20 @@ typedef struct
 /* Types that are different depending on shared/unshared unix binaries */
 #define LABENT_LNR_OFFSET lnr_adr
 
+/* When a routine is recursively linked, the old routine hdr/label table are copied and
+ * attached to active_rhead_adr pointer of the replaced routine header. At unwind or goto time,
+ * we check if these copies can be cleaned up with the following macro.
+ */
+#define CLEANUP_COPIED_RECURSIVE_RTN(RTNHDR)											\
+{																\
+	/* For USHBIN_SUPPORTED routines, if the rtn_relinked flag is ON in the routine header (which results from not cleaning	\
+	 * up a routine when it is either explicitly or automatically re-linked), check if the stack contains any more		\
+	 * references to this routine header. If not, it is ripe for cleanup as it has been replaced so drive zr_unlink_rtn()	\
+	 * on it.														\
+	 */															\
+	if ((RTNHDR)->rtn_relinked)												\
+		zr_cleanup_recursive_rtn(RTNHDR);										\
+}
 /* Format of a relocation datum. */
 struct	relocation_info
 {
@@ -221,7 +272,7 @@ struct	sym_table
 #define NOVERIFY	FALSE
 
 /* Prototypes */
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
 void free_src_tbl(rhdtyp *rtn_vector);
 unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
 int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
@@ -239,5 +290,12 @@ char *rtnlaboff2entryref(char *entryref_buff, mident *rtn, mident *lab, int offs
 boolean_t on_stack(rhdtyp *rtnhdr, boolean_t *need_duplicate);
 rhdtyp *op_rhd_ext(mval *rtname, mval *lblname, rhdtyp *rhd, void *lnr);
 void *op_lab_ext(void);
+void zr_cleanup_recursive_rtn(rhdtyp *rtnhdr);
+#ifdef AUTORELINK_SUPPORTED
+#include "zroutinessp.h"	/* Needed for zro_ent type for zro_record_zhist declaration */
+boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist);
+zro_hist *zro_zhist_saverecent(zro_search_hist_ent *zhist_valent, zro_search_hist_ent *zhist_valent_base);
+void zro_record_zhist(zro_search_hist_ent *zhist_valent, zro_ent *obj_container, mstr *rtnname);
+#endif /* AUTORELINK_DEFINED */
 
 #endif /* RTNHDR_H_INCLUDED */
diff --git a/sr_unix/rtnobj.c b/sr_unix/rtnobj.c
new file mode 100644
index 0000000..cd10223
--- /dev/null
+++ b/sr_unix/rtnobj.c
@@ -0,0 +1,997 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made available	*
+ *	under a license.  If you do not know the terms of	*
+ *	the license, please stop and do not read further.	*
+ *								*
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#include "gtm_ipc.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include "rtnobj.h"
+#include "gtmio.h"
+#include <rtnhdr.h>
+#include "iosp.h"
+#include "do_shmat.h"
+#include "min_max.h"
+#include "relqop.h"
+#include "ipcrmid.h"
+#include "interlock.h"
+#include "gdsroot.h"	/* for CDB_STAGNATE */
+#include "incr_link.h"	/* for NATIVE_HDR_LEN */
+#include "hugetlbfs_overrides.h"	/* for the ADJUST_SHM_SIZE_FOR_HUGEPAGES macro */
+#include "gtm_permissions.h"
+#include "cachectl.h"
+#include "cacheflush.h"
+
+/* Uncomment below line if you want RTNOBJ_DBG lines to be enabled */
+/* #define RTNOBJ_DEBUG */
+
+#ifdef RTNOBJ_DEBUG
+#	define RTNOBJ_DBG(X)	X
+#else
+#	define RTNOBJ_DBG(X)
+#endif
+
+#define	CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK)			\
+{												\
+	if (!HAS_RELINKCTL_LOCK)								\
+	{	/* If we dont have a lock, and MIN_INDEX/MAX_INDEX are invalid, redo loop	\
+		 * until we find valid values. After a few redos, get a lock before the search.	\
+		 */										\
+		if ((0 > MIN_INDEX) || (NUM_RTNOBJ_SHM_INDEX < MIN_INDEX)			\
+			|| (0 > MAX_INDEX) || (NUM_RTNOBJ_SHM_INDEX < MAX_INDEX))		\
+		{										\
+			continue;								\
+		}										\
+	} else											\
+	{											\
+		assert(0 <= MIN_INDEX);								\
+		assert(NUM_RTNOBJ_SHM_INDEX >= MIN_INDEX);					\
+		assert(0 <= MAX_INDEX);								\
+		assert(NUM_RTNOBJ_SHM_INDEX >= MAX_INDEX);					\
+	}											\
+}
+
+#define	SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(LINKCTL, MIN_INDEX, MAX_INDEX, SHM_HDR, HAS_RELINKCTL_LOCK, RELINKREC)		\
+{																\
+	int		cycle, i, pvt_shmid, shr_shmid;										\
+	int		save_errno;												\
+	size_t		shm_size;												\
+	sm_uc_ptr_t	shm_base;												\
+	char		errstr[256];												\
+																\
+	cycle = SHM_HDR->rtnobj_shmid_cycle;											\
+	/* NARSTODO: Need memory barrier? Since cycle/MIN_INDEX/MAX_INDEX could be read out-of-order */				\
+	if (LINKCTL->rtnobj_shmid_cycle != cycle)										\
+	{															\
+		MIN_INDEX = SHM_HDR->rtnobj_min_shm_index;									\
+		MAX_INDEX = SHM_HDR->rtnobj_max_shm_index;									\
+		/* Check integrity of min_index/max_index */									\
+		CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK);						\
+		for (i = MIN_INDEX; i < MAX_INDEX; i++)										\
+		{														\
+			pvt_shmid = LINKCTL->rtnobj_shmid[i];									\
+			shr_shmid = SHM_HDR->rtnobj_shmhdr[i].rtnobj_shmid;							\
+			if (pvt_shmid != shr_shmid)										\
+			{													\
+				assert(INVALID_SHMID == pvt_shmid); /* currently rtnobj shmids are never deleted */		\
+				shm_size = ((size_t)1 << (i + MIN_RTNOBJ_SHM_INDEX));						\
+				shm_base = (sm_uc_ptr_t)do_shmat_exec_perm(shr_shmid, shm_size, &save_errno);			\
+				if (-1 == (sm_long_t)shm_base)									\
+				{												\
+					if (HAS_RELINKCTL_LOCK)									\
+						rel_latch(&SHM_HDR->relinkctl_latch);						\
+					rel_latch(&RELINKREC->rtnobj_latch);							\
+					SNPRINTF(errstr, SIZEOF(errstr), "rtnobj2 shmat() failed for shmid=%d shmsize=0x%llx",	\
+						shr_shmid, shm_size);								\
+					ISSUE_RELINKCTLERR_SYSCALL(&LINKCTL->zro_entry_name, errstr, save_errno);		\
+				}												\
+				assert(0 == ((UINTPTR_T)shm_base % 8));								\
+				LINKCTL->rtnobj_shmid[i] = shr_shmid;								\
+				LINKCTL->rtnobj_shm_base[i] = shm_base;								\
+			}													\
+		}														\
+		LINKCTL->rtnobj_min_shm_index = min_index;									\
+		LINKCTL->rtnobj_max_shm_index = max_index;									\
+		LINKCTL->rtnobj_shmid_cycle = cycle;										\
+	} else															\
+	{															\
+		MIN_INDEX = linkctl->rtnobj_min_shm_index;									\
+		MAX_INDEX = linkctl->rtnobj_max_shm_index;									\
+		CONTINUE_IF_INDEX_INVALID(MIN_INDEX, MAX_INDEX, HAS_RELINKCTL_LOCK);						\
+	}															\
+}
+
+#ifdef AUTORELINK_SUPPORTED
+
+error_def(ERR_PERMGENFAIL);
+error_def(ERR_RELINKCTLERR);
+error_def(ERR_RLNKRECLATCH);
+error_def(ERR_RLNKSHMLATCH);
+error_def(ERR_SYSCALL);
+
+DEBUG_ONLY(GBLREF int	saved_errno;)
+
+#ifdef DEBUG
+void	rtnobj_verify_freelist_fl_bl(rtnobjshm_hdr_t *rtnobj_shm_hdr, sm_uc_ptr_t shm_base)
+{
+	int		min_index, max_index, i;
+	que_ent_ptr_t	freeList, elem, prev_elem;
+	rtnobj_hdr_t	*rtnobj, *rtnobj2;
+	sm_off_t	rtnobj_off;
+	gtm_uint64_t	elemSize;
+	sm_uc_ptr_t	shm_top;
+
+	freeList = &rtnobj_shm_hdr->freeList[0];
+	shm_top = shm_base + rtnobj_shm_hdr->shm_len;
+	for (i = 0; i < NUM_RTNOBJ_SIZE_BITS; i++, freeList++)
+	{
+		if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+		{
+			assert(NULL_RTNOBJ_SM_OFF_T != freeList->bl);
+			assert(0 == freeList->fl % 8);
+			prev_elem = NULL;
+			elem = (que_ent_ptr_t)(shm_base + freeList->fl);
+			do
+			{
+				rtnobj = (rtnobj_hdr_t *)((sm_uc_ptr_t)elem - OFFSETOF(rtnobj_hdr_t, userStorage));
+				assert(STATE_FREE == rtnobj->state);
+				assert(i == rtnobj->queueIndex);
+				rtnobj_off = (sm_uc_ptr_t)rtnobj - shm_base;
+				elemSize = ((gtm_uint64_t)1 << (rtnobj->queueIndex + MIN_RTNOBJ_SIZE_BITS));
+				rtnobj2 = (rtnobj_hdr_t *)(shm_base + (rtnobj_off ^ elemSize));	/* address of buddy */
+				assert(((sm_uc_ptr_t)rtnobj2 == shm_top) || (rtnobj2->queueIndex <= rtnobj->queueIndex));
+				if (NULL_RTNOBJ_SM_OFF_T == elem->bl)
+					assert(NULL == prev_elem);
+				else
+					assert(((NULL == prev_elem) && (NULL_RTNOBJ_SM_OFF_T == elem->bl))
+						|| (prev_elem->fl == -elem->bl));
+				if (NULL_RTNOBJ_SM_OFF_T == elem->fl)
+				{
+					assert(elem == (que_ent_ptr_t)(shm_base + freeList->bl));
+					break;
+				}
+				assert(0 == elem->fl % 8);
+				prev_elem = elem;
+				elem = (que_ent_ptr_t)((sm_uc_ptr_t)elem + elem->fl);
+			}
+			while (TRUE);
+		} else
+			assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+	}
+}
+
+void	rtnobj_verify_min_max_free_index(rtnobjshm_hdr_t *rtnobj_shm_hdr)
+{
+	int		min_index, max_index, i;
+	que_ent_ptr_t	freeList;
+
+	min_index = NUM_RTNOBJ_SIZE_BITS;
+	max_index = 0;
+	freeList = &rtnobj_shm_hdr->freeList[0];
+	for (i = 0; i < NUM_RTNOBJ_SIZE_BITS; i++, freeList++)
+	{
+		if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+		{
+			if (min_index > i)
+				min_index = i;
+			if (max_index < (i + 1))
+				max_index = i + 1;
+		}
+	}
+	assert(min_index == rtnobj_shm_hdr->rtnobj_min_free_index);
+	assert(max_index == rtnobj_shm_hdr->rtnobj_max_free_index);
+}
+#endif
+
+/* Insert an element at the tail of the queue */
+void	insqt_rtnobj(que_ent_ptr_t new_tail, que_ent_ptr_t que_base, sm_uc_ptr_t shm_base)
+{
+	que_ent_ptr_t old_tail;
+
+	RTNOBJ_DBG(fprintf(stderr, "insqt_rtnobj : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n",		\
+		(long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)new_tail);)
+	if (NULL_RTNOBJ_SM_OFF_T == que_base->bl)
+	{	/* Queue has nothing */
+		assert(NULL_RTNOBJ_SM_OFF_T == que_base->fl);
+		que_base->fl = (uchar_ptr_t)new_tail - (uchar_ptr_t)shm_base;
+		assert(0 == que_base->fl % 8);
+		que_base->bl = que_base->fl;
+		new_tail->fl = NULL_RTNOBJ_SM_OFF_T;
+		new_tail->bl = NULL_RTNOBJ_SM_OFF_T;
+	} else
+	{
+		old_tail = (que_ent_ptr_t)(shm_base + que_base->bl);
+		assert(NULL_RTNOBJ_SM_OFF_T == old_tail->fl);
+		new_tail->fl = NULL_RTNOBJ_SM_OFF_T;
+		new_tail->bl = (uchar_ptr_t)old_tail - (uchar_ptr_t)new_tail;
+		assert(0 == new_tail->bl % 8);
+		old_tail->fl = -new_tail->bl;
+		que_base->bl += old_tail->fl;
+	}
+	return;
+}
+
+/* Remove an element from the head of the queue */
+rtnobj_hdr_t *remqh_rtnobj(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base)
+{
+	que_ent_ptr_t	ret, new_head;
+	rtnobj_hdr_t	*rtnobj;
+
+	assert(NULL_RTNOBJ_SM_OFF_T != que_base->fl);
+	ret = (que_ent_ptr_t)(shm_base + que_base->fl);
+	RTNOBJ_DBG(fprintf(stderr, "remqh_rtnobj : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n",		\
+		(long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)ret);)
+	assert(0 == (sm_off_t)ret % 8);
+	assert(NULL_RTNOBJ_SM_OFF_T == ret->bl);
+	if (NULL_RTNOBJ_SM_OFF_T == ret->fl)
+	{	/* Empty queue after this removal */
+		que_base->fl = NULL_RTNOBJ_SM_OFF_T;
+		que_base->bl = NULL_RTNOBJ_SM_OFF_T;
+	} else
+	{
+		new_head = (que_ent_ptr_t)((uchar_ptr_t)ret + ret->fl);
+		assert(0 == (sm_off_t)new_head % 8);
+		new_head->bl = NULL_RTNOBJ_SM_OFF_T;
+		assert(0 == que_base->fl % 8);
+		que_base->fl += ret->fl;
+	}
+	rtnobj = (rtnobj_hdr_t *)((sm_uc_ptr_t)ret - OFFSETOF(rtnobj_hdr_t, userStorage));
+	return rtnobj;
+}
+
+/* Remove a specific element "rtnobj" from wherever it is in the queue */
+void	remq_rtnobj_specific(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base, rtnobj_hdr_t *rtnobj)
+{
+	que_ent_ptr_t	elem, new_head, rtnque;
+
+	assert(NULL_RTNOBJ_SM_OFF_T != que_base->fl);
+	rtnque = (que_ent_ptr_t)((sm_uc_ptr_t)rtnobj + OFFSETOF(rtnobj_hdr_t, userStorage));
+	RTNOBJ_DBG(fprintf(stderr, "remqh_rtnobj_specific : que_base = 0x%llx : shm_base = 0x%llx : elem = 0x%llx\n",	\
+		(long long unsigned int)que_base, (long long unsigned int)shm_base, (long long unsigned int)rtnque);)
+#	ifdef DEBUG
+	/* Verify that "rtnobj" is actually in the queue first */
+	elem = (que_ent_ptr_t)(shm_base + que_base->fl);
+	assert(NULL_RTNOBJ_SM_OFF_T == elem->bl);
+	while (elem != rtnque)
+	{
+		assert(NULL_RTNOBJ_SM_OFF_T != elem->fl);
+		elem = (que_ent_ptr_t)((sm_uc_ptr_t)elem + elem->fl);
+	}
+#	endif
+	if (NULL_RTNOBJ_SM_OFF_T == rtnque->bl)
+	{	/* rtnobj is at head of queue */
+		if (NULL_RTNOBJ_SM_OFF_T == rtnque->fl)
+		{	/* rtnobj is only element in queue */
+			que_base->fl = NULL_RTNOBJ_SM_OFF_T;
+			que_base->bl = NULL_RTNOBJ_SM_OFF_T;
+		} else
+		{
+			elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->fl);
+			assert(0 == (sm_off_t)elem % 8);
+			elem->bl = NULL_RTNOBJ_SM_OFF_T;
+			assert(0 == que_base->fl % 8);
+			assert(0 == rtnque->fl % 8);
+			que_base->fl += rtnque->fl;
+		}
+	} else if (NULL_RTNOBJ_SM_OFF_T == rtnque->fl)
+	{	/* rtnobj is at tail of queue with at least one more element in queue */
+		elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->bl);
+		elem->fl = NULL_RTNOBJ_SM_OFF_T;
+		assert(0 == que_base->bl % 8);
+		assert(0 == rtnque->bl % 8);
+		que_base->bl += rtnque->bl;
+	} else
+	{	/* rtnobj is in middle of queue with at least one element in queue on either side */
+		elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->bl);
+		assert(0 == (sm_off_t)elem % 8);
+		assert(0 == elem->fl % 8);
+		assert(0 == rtnque->fl % 8);
+		elem->fl += rtnque->fl;
+		assert(0 == (sm_off_t)rtnque % 8);
+		assert(0 == rtnque->fl % 8);
+		elem = (que_ent_ptr_t)((uchar_ptr_t)rtnque + rtnque->fl);
+		assert(0 == elem->bl % 8);
+		assert(0 == rtnque->bl % 8);
+		elem->bl += rtnque->bl;
+	}
+}
+
+sm_uc_ptr_t rtnobj_shm_malloc(zro_hist *zhist, int fd, off_t objSize, gtm_uint64_t objhash)
+{
+	boolean_t		has_relinkctl_lock, has_rtnobj_lock;
+	boolean_t		initialized, return_NULL;
+	char			errstr[256];
+	gtm_uint64_t		src_cksum_8byte;
+	int			min_index, max_index, min_free_index, max_free_index, shm_index;
+	int			objIndex, tSize, sizeIndex, shmSizeIndex, shmid, actualSize;
+	int			codelen, loopcnt, save_errno;
+	open_relinkctl_sgm	*linkctl;
+	que_ent_ptr_t		freeList;
+	relinkrec_t		*relinkrec;
+	relinkshm_hdr_t		*shm_hdr;
+	sm_uc_ptr_t		shm_base;
+	rtnobj_hdr_t		*rtnobj, *prev_rtnobj, *rtnobj2;
+	rtnobj_sm_off_t		shm_index_off;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	size_t			shm_size;
+	off_t			rtnobjSize;
+	sm_off_t		shm_off;
+	sm_uc_ptr_t		objBuff, codeadr;
+	rhdtyp			tmprhd, *rhdr;
+	gtm_uint64_t		elemSize;
+	zro_validation_entry	*zhent;
+	char			zro_entry_str[ZRO_DIR_PATH_MAX + 1];
+	struct stat		dir_stat_buf;
+	int			stat_res;
+	int			user_id;
+	int			group_id;
+	int			perm;
+	int			maxvers, curvers;
+	struct perm_diag_data	pdd;
+	struct shmid_ds		shmstat;
+#	ifdef DEBUG
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+#	endif
+	zhent = zhist->end - 1;
+	relinkrec = zhent->relinkrec;
+	linkctl = zhent->relinkctl_bkptr;
+	/* Assert certain design assumptions */
+	assert((MAX_RTNOBJ_SHM_INDEX + RTNOBJ_SHMID_INDEX_MAXBITS) <= (8 * SIZEOF(rtnobj_sm_off_t)));
+	assert(((size_t)1 << RTNOBJ_SHMID_INDEX_MAXBITS) >= MAX_RTNOBJ_SHM_INDEX);
+	/* Check if we are in sync with shared memory. If not attach to requisite shmids first.
+	 * Note that the below logic tries to do search outside of any locks (for performance reasons)
+	 * but that means we need to be extra careful in validating things read outside of a lock.
+	 */
+	shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+	loopcnt = 0;
+	has_relinkctl_lock = FALSE;
+	assert(!linkctl->locked);
+	assert(!linkctl->hdr->file_deleted);
+	if (!grab_latch(&relinkrec->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC))
+	{
+		assert(FALSE);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+				ERR_RLNKRECLATCH, 3, relinkrec->rtnname_fixed.c, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+	}
+	memcpy(zro_entry_str, linkctl->zro_entry_name.addr, linkctl->zro_entry_name.len);
+	zro_entry_str[linkctl->zro_entry_name.len] = '\0';
+	do
+	{
+		if (CDB_STAGNATE <= loopcnt++)
+		{	/* We have tried THRICE to search without a lock but found something inconsistent (due to concurrent
+			 * changes to shared memory structures). Get a lock on the entire relinkctl file before searching
+			 * for one last time.
+			 */
+			assert(!has_relinkctl_lock);
+			if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+			{
+				assert(FALSE);
+				rel_latch(&relinkrec->rtnobj_latch);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+						ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+			}
+			has_relinkctl_lock = TRUE;
+		}
+		SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(linkctl, min_index, max_index, shm_hdr, has_relinkctl_lock, relinkrec);
+			/* note: the above macro could do a "continue" if "has_relinkctl_lock" is FALSE */
+		/* Now that we have attached to the necessary routine buffer shmids, search within shared memory for the
+		 * routine buffer whose <objhash,objLen> matches ours.
+		 */
+		assert(MAXUINT4 >= objSize);
+		shm_index_off = relinkrec->rtnobj_shm_offset;
+		prev_rtnobj = NULL;
+		maxvers = relinkrec->numvers;
+		curvers = 0;
+		while ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+		{
+			assertpro(maxvers >= curvers++);	/* assertpro to avoid infinite loops in PRO (just in case) */
+			shm_index = RTNOBJ_GET_SHM_INDEX(shm_index_off);
+			shm_off = RTNOBJ_GET_SHM_OFFSET(shm_index_off);
+			assert(0 == (shm_off % 8));
+			/* Since we hold the rtnobj_latch we should see valid values of shm_index/shm_off */
+			assert(min_index <= shm_index);
+			assert(max_index > shm_index);
+			assert(INVALID_SHMID != linkctl->rtnobj_shmid[shm_index]);
+			assert(shm_off < ((off_t)1 << (MIN_RTNOBJ_SHM_INDEX + shm_index)));
+			rtnobj = (rtnobj_hdr_t *)(linkctl->rtnobj_shm_base[shm_index] + shm_off);
+			assert((rtnobj->objhash != objhash) || (rtnobj->objLen == objSize));
+			if ((rtnobj->objLen == objSize) && (rtnobj->objhash == objhash))
+				break;
+			prev_rtnobj = rtnobj;
+			shm_index_off = rtnobj->next_rtnobj_shm_offset;
+		}
+		if ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+		{	/* If found return */
+			assert(rtnobj->initialized);
+			/* If gtm_autorelink_keeprtn is FALSE (i.e. we maintain reference counts even on process exit),
+			 * we do not expect refcnt to go to high values as it is the # of processes concurrently running
+			 * and actively using this buffer and that cannot be close to 2**31 which is the max value for refcnt.
+			 */
+			assert(TREF(gtm_autorelink_keeprtn) || (REFCNT_INACCURATE != rtnobj->refcnt));
+			if (REFCNT_INACCURATE != rtnobj->refcnt)
+				rtnobj->refcnt++;	/* increment refcnt while holding the rtnobj_lock */
+			if (has_relinkctl_lock)
+				rel_latch(&shm_hdr->relinkctl_latch);
+			RTNOBJ_DBG(fprintf(stderr, "rtnobj_shm_malloc : rtnname = %s : objhash = 0x%llx : "		\
+				"linkctl = 0x%llx : Found : refcnt = %d : elem = 0x%llx\n",				\
+				relinkrec->rtnname_fixed.c, (long long unsigned int)objhash,				\
+				(long long unsigned int)linkctl, rtnobj->refcnt,					\
+				(long long unsigned int)&rtnobj->userStorage.userStart);)
+			zhent->cycle = relinkrec->cycle;	/* Update private cycle to be in sync with shared copy */
+			rel_latch(&relinkrec->rtnobj_latch);
+			objBuff = (sm_uc_ptr_t)&rtnobj->userStorage.userStart;
+			return objBuff;	/* object code starts after rtnobj_hdr_t */
+		}
+		assert(MAXUINT4 >= (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+		assert(4 <= SIZEOF(tSize));	/* above assert guarantees 4-bytes is enough for storage */
+		tSize = objSize + OFFSETOF(rtnobj_hdr_t, userStorage);
+		sizeIndex = ceil_log2_32bit(tSize);
+		assert(MAX_RTNOBJ_SIZE_BITS >= sizeIndex);
+		sizeIndex = MAX(sizeIndex, MIN_RTNOBJ_SIZE_BITS);	/* Round up to minimum supported obj file size */
+		/* Find the smallest shm index that can possibly contain space for sizeIndex */
+		shm_index = (MIN_RTNOBJ_SHM_INDEX > sizeIndex) ? 0 : sizeIndex - MIN_RTNOBJ_SHM_INDEX;
+		sizeIndex -= MIN_RTNOBJ_SIZE_BITS;
+		shm_index = MAX(shm_index, shm_hdr->min_shm_index);
+		/* If not found, allocate space in shared memory for one and return. Now that we are going to
+		 * play with the buddy list structures in shared memory, get an overarching lock on all rtnobj shmids
+		 * i.e. a lock on the entire relinkctl file
+		 */
+		if (!has_relinkctl_lock)
+		{
+			if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+			{
+				assert(FALSE);
+				rel_latch(&relinkrec->rtnobj_latch);
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+						ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+			}
+			has_relinkctl_lock = TRUE;
+		}
+		/* Sync up with rtnobj shmids one final time if needed now that we have the relinkctl file lock */
+		SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED(linkctl, min_index, max_index, shm_hdr, has_relinkctl_lock, relinkrec);
+			/* note: the above macro is guaranteed not to do a "continue" since "has_relinkctl_lock" is TRUE */
+		/* Find a shared memory buffer to hold the routine object */
+		rtnobj = NULL;
+		for ( ; shm_index < max_index; shm_index++)
+		{
+			rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+			if (INVALID_SHMID == rtnobj_shm_hdr->rtnobj_shmid)
+				continue;
+			min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+			max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+			shm_base = linkctl->rtnobj_shm_base[shm_index];
+			objIndex = MAX(sizeIndex, min_free_index);
+			freeList = &rtnobj_shm_hdr->freeList[objIndex];
+			for ( ; objIndex < max_free_index; objIndex++, freeList++)
+			{
+				assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+				if (NULL_RTNOBJ_SM_OFF_T == freeList->fl)
+				{
+					assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+					continue;
+				}
+				rtnobj = remqh_rtnobj(freeList, shm_base);
+				if (NULL_RTNOBJ_SM_OFF_T == freeList->fl)
+				{
+					assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+					/* This was the only element in the freeList.
+					 * Set min_free_index/max_free_index to impossible values
+					 * if the new minimums/maximums need to be recomputed.
+					 */
+					if (objIndex == min_free_index)
+						min_free_index = NUM_RTNOBJ_SIZE_BITS;
+					if (max_free_index == (objIndex + 1))
+						max_free_index = 0;
+				} else if (min_free_index > sizeIndex)
+				{
+					assert(NUM_RTNOBJ_SIZE_BITS > min_free_index);
+					min_free_index = NUM_RTNOBJ_SIZE_BITS;
+				}
+				break;
+			}
+			if (NULL != rtnobj)
+				break;
+		}
+		if (NULL == rtnobj)
+		{	/* Need to allocate rtnobj buffer in a new shared memory segment */
+			assert(shm_index >= max_index);
+			shm_size = ((size_t)1 << (shm_index + MIN_RTNOBJ_SHM_INDEX));
+			ADJUST_SHM_SIZE_FOR_HUGEPAGES(shm_size, shm_size); /* second parameter "shm_size" is adjusted size */
+			/* If minimum huge page size is much higher than requested shm size, adjust "shm_index"
+			 * accordingly so we use the allocated (bigger-than-requested) shm completely.
+			 */
+			shmSizeIndex = ceil_log2_64bit(shm_size);
+			assert(((size_t)1 << shmSizeIndex) == shm_size);
+			assert(shmSizeIndex >= (shm_index + MIN_RTNOBJ_SHM_INDEX));
+			shm_index = shmSizeIndex - MIN_RTNOBJ_SHM_INDEX;
+			shmid = shmget(IPC_PRIVATE, shm_size, RWDALL | IPC_CREAT);
+			if (-1 == shmid)
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmget() failed for shmsize=0x%llx", shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			STAT_FILE(zro_entry_str, &dir_stat_buf, stat_res);
+			if (-1 == stat_res)
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "rtnobj stat() of file %s failed", zro_entry_str);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			if (gtm_permissions(&dir_stat_buf, &user_id, &group_id, &perm, PERM_IPC|PERM_EXEC, &pdd) < 0)
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10)
+						ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name),
+						ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("rtnobj"),
+						RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+			}
+			if (-1 == shmctl(shmid, IPC_STAT, &shmstat))
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmctl(IPC_STAT) failed for shmid=%d shmsize=0x%llx",
+					shmid, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			/* change group and permissions */
+			if ((-1 != user_id) && (user_id != shmstat.shm_perm.uid))
+				shmstat.shm_perm.uid = user_id;
+			if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid))
+				shmstat.shm_perm.gid = group_id;
+			shmstat.shm_perm.mode = perm;
+			if (-1 == shmctl(shmid, IPC_SET, &shmstat))
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmctl(IPC_SET) failed for shmid=%d shmsize=0x%llx",
+					shmid, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			shm_base = (sm_uc_ptr_t)do_shmat_exec_perm(shmid, shm_size, &save_errno);
+			if (-1 == (sm_long_t)shm_base)
+			{
+				save_errno = errno;
+				rel_latch(&shm_hdr->relinkctl_latch);
+				rel_latch(&relinkrec->rtnobj_latch);
+				shm_rmid(shmid);	/* if error removing shmid we created, just move on */
+				SNPRINTF(errstr, SIZEOF(errstr), "rtnobj shmat() failed for shmid=%d shmsize=0x%llx",
+					shmid, shm_size);
+				ISSUE_RELINKCTLERR_SYSCALL(&linkctl->zro_entry_name, errstr, save_errno);
+			}
+			assert(shm_index < NUM_RTNOBJ_SHM_INDEX);
+			rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+			objIndex = (shm_index + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS);
+			assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+			freeList = &rtnobj_shm_hdr->freeList[objIndex];
+			rtnobj = (rtnobj_hdr_t *)shm_base;
+			assert(NULL_RTNOBJ_SM_OFF_T == freeList->fl);
+			assert(NULL_RTNOBJ_SM_OFF_T == freeList->bl);
+			assert(sizeIndex <= objIndex);
+			if (sizeIndex < objIndex)
+			{	/* rtnobj_shm_hdr->rtnobj_min_free_index and ->rtnobj_min_free_index will be set a little later */
+				min_free_index = NUM_RTNOBJ_SIZE_BITS;
+				max_free_index = 0;
+			} else
+			{	/* rtnobj_shm_hdr->rtnobj_min_free_index and ->rtnobj_min_free_index are already set correctly.
+				 * set min_free_index/max_free_index such that the above two dont get set again (a little later).
+				 */
+				assert(NUM_RTNOBJ_SIZE_BITS == rtnobj_shm_hdr->rtnobj_min_free_index);
+				assert(0 == rtnobj_shm_hdr->rtnobj_max_free_index);
+				assert(NUM_RTNOBJ_SIZE_BITS != objIndex);
+				min_free_index = objIndex;
+				assert(0 != NUM_RTNOBJ_SIZE_BITS);
+				max_free_index = NUM_RTNOBJ_SIZE_BITS;
+			}
+			rtnobj_shm_hdr->rtnobj_shmid = shmid;
+			assert(0 == rtnobj_shm_hdr->real_len);
+			rtnobj_shm_hdr->shm_len = shm_size;
+			if (shm_hdr->rtnobj_min_shm_index > shm_index)
+			{
+				assert(0 == shm_hdr->rtnobj_shmid_cycle); /* our shm expansion logic must not reach this codepath */
+				shm_hdr->rtnobj_min_shm_index = shm_index;
+			}
+			if (shm_hdr->rtnobj_max_shm_index < (shm_index + 1))
+				shm_hdr->rtnobj_max_shm_index = (shm_index + 1);
+			/* Sync shared memory with private contents for this process to avoid duplicate shmget/shmat */
+			assert(linkctl->rtnobj_shmid_cycle == shm_hdr->rtnobj_shmid_cycle);	/* due to SYNC_* done above */
+			shm_hdr->rtnobj_shmid_cycle++;
+			linkctl->rtnobj_shmid_cycle = shm_hdr->rtnobj_shmid_cycle;
+			linkctl->rtnobj_min_shm_index = shm_hdr->rtnobj_min_shm_index;
+			linkctl->rtnobj_max_shm_index = shm_hdr->rtnobj_max_shm_index;
+			linkctl->rtnobj_shm_base[shm_index] = shm_base;
+			linkctl->rtnobj_shmid[shm_index] = shmid;
+		}
+		/* At this point, we have a non-null rtnobj but it could be bigger than we want.
+		 * Split it into half until we reach the desired size. Insert into free queues along the way.
+		 */
+		assert(objIndex >= sizeIndex);
+		if (objIndex > sizeIndex)
+		{
+			if (0 == max_free_index)
+			{
+				rtnobj_shm_hdr->rtnobj_max_free_index = objIndex;
+				max_free_index = objIndex;
+			}
+			rtnobjSize = ((off_t)1 << (objIndex + MIN_RTNOBJ_SIZE_BITS));
+			freeList = &rtnobj_shm_hdr->freeList[objIndex];
+			do
+			{
+				rtnobjSize /= 2;
+				objIndex--;
+				freeList--;
+				rtnobj2 = (rtnobj_hdr_t *)((sm_uc_ptr_t)rtnobj + rtnobjSize);
+				rtnobj2->state = STATE_FREE;
+				rtnobj2->queueIndex = objIndex;
+				DEBUG_ONLY(shm_off = (sm_uc_ptr_t)rtnobj2 - shm_base);
+				assert(0 == (shm_off % ((sm_off_t)1 << (objIndex + MIN_RTNOBJ_SIZE_BITS))));
+				/* rtnobj2->initialized            needs initialization only when state becomes STATE_ALLOCATED */
+				/* rtnobj2->refcnt                 needs initialization only when state becomes STATE_ALLOCATED */
+				/* rtnobj2->src_cksum_8byte        needs initialization only when state becomes STATE_ALLOCATED */
+				/* rtnobj2->next_rtnobj_shm_offset needs initialization only when state becomes STATE_ALLOCATED */
+				/* rtnobj2->relinkctl_index        needs initialization only when state becomes STATE_ALLOCATED */
+				/* rtnobj2->objLen                 needs initialization only when state becomes STATE_ALLOCATED */
+				insqt_rtnobj(&rtnobj2->userStorage.freePtr, freeList, shm_base);
+			} while (objIndex > sizeIndex);
+			if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+				rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex;
+		} else
+		{
+			if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+			{
+				assert(objIndex == rtnobj_shm_hdr->rtnobj_min_free_index);
+				if (0 == max_free_index)
+				{	/* Need to recompute BOTH rtnobj_shm_hdr->rtnobj_min_free_index
+					 * AND rtnobj_shm_hdr->rtnobj_max_free_index. But the fact that
+					 * min and max are the same implies there are NO more free buffers
+					 * in this entire shared memory so the recomputation is easy.
+					 */
+					assert((objIndex + 1) == rtnobj_shm_hdr->rtnobj_max_free_index);
+					rtnobj_shm_hdr->rtnobj_max_free_index = 0;
+					rtnobj_shm_hdr->rtnobj_min_free_index = NUM_RTNOBJ_SIZE_BITS;
+				} else
+				{	/* Need to ONLY recompute rtnobj_shm_hdr->rtnobj_min_free_index */
+					max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+					freeList = &rtnobj_shm_hdr->freeList[objIndex];
+					for ( ; objIndex < max_free_index; objIndex++, freeList++)
+					{
+						assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+						if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+						{
+							rtnobj_shm_hdr->rtnobj_min_free_index = objIndex;
+							break;
+						}
+					}
+					assert(objIndex < max_free_index);
+				}
+			} else if (0 == max_free_index)
+			{	/* Need to ONLY recompute rtnobj_shm_hdr->rtnobj_min_free_index */
+				assert((objIndex + 1) == rtnobj_shm_hdr->rtnobj_max_free_index);
+				min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+				freeList = &rtnobj_shm_hdr->freeList[objIndex];
+				for ( ; objIndex >= min_free_index; objIndex--, freeList--)
+				{
+					assert(objIndex < NUM_RTNOBJ_SIZE_BITS);
+					if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+					{
+						rtnobj_shm_hdr->rtnobj_max_free_index = objIndex + 1;
+						break;
+					}
+				}
+				assert(objIndex >= min_free_index);
+			}
+		}
+		rtnobj->state = STATE_ALLOCATED;
+		rtnobj->queueIndex = sizeIndex;
+		rtnobj_shm_hdr->real_len += objSize;
+		elemSize = ((gtm_uint64_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS));
+		rtnobj_shm_hdr->used_len += elemSize;
+		DEBUG_ONLY(rtnobj_verify_min_max_free_index(rtnobj_shm_hdr));
+		DEBUG_ONLY(rtnobj_verify_freelist_fl_bl(rtnobj_shm_hdr, shm_base);)
+		/* Now that we have gotten a "rtnobj" pointer, we can release the relinkctl latch on shared memory.
+		 * We still need to hold on to the lower-granular relinkrec->rtnobj_latch to read the object file
+		 * into shared memory.
+		 */
+		rel_latch(&shm_hdr->relinkctl_latch);
+		assert(((off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS)) >= (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+		assert(((off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS - 1)) < (objSize + OFFSETOF(rtnobj_hdr_t, userStorage)));
+		shm_off = (sm_uc_ptr_t)rtnobj - shm_base;
+		assert(0 == (shm_off % ((sm_off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS))));
+		rtnobj->initialized = TRUE;
+		rtnobj->refcnt = 1;
+		assert(0 <= shm_off);
+		assert(shm_off < rtnobj_shm_hdr->shm_len);
+		shm_index_off = RTNOBJ_SET_SHM_INDEX_OFF(shm_index, shm_off);
+		if (NULL != prev_rtnobj)
+			prev_rtnobj->next_rtnobj_shm_offset = shm_index_off;
+		else
+			relinkrec->rtnobj_shm_offset = shm_index_off;
+		rtnobj->next_rtnobj_shm_offset = (rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T;
+		rtnobj->relinkctl_index = relinkrec - linkctl->rec_base;
+		rtnobj->objLen = objSize;
+		rtnobj->objhash = objhash;
+		relinkrec->objLen += objSize;
+		relinkrec->usedLen += elemSize;
+		relinkrec->numvers++;
+		/* Fill the shared memory buffer with the object code */
+		objBuff = (sm_uc_ptr_t)&rtnobj->userStorage.userStart;
+		if (-1 == lseek(fd, NATIVE_HDR_LEN, SEEK_SET))
+			return_NULL = TRUE;
+		else
+		{
+			DOREADRL(fd, objBuff, objSize, actualSize);
+			return_NULL = (actualSize != objSize);
+		}
+		if (return_NULL)
+		{
+			/* Free allocated object in shared memory using rtnobj_shm_free. Set up a dummy rtnhdr
+			 * with just the necessary fields initialized since rtnobj_shm_free requires it.
+			 */
+			rhdr = &tmprhd;
+			rhdr->shared_ptext_adr = objBuff + SIZEOF(rhdtyp);
+			rhdr->zhist = zhist;
+			DEBUG_ONLY(rhdr->shared_object = TRUE);	/* for an assert inside rtnobj_shm_free */
+			DEBUG_ONLY(rhdr->relinkctl_bkptr = linkctl);	/* for an assert inside rtnobj_shm_free */
+			/* We already hold the relinkrec->rtnobj_latch. Free up the shared object before releasing this
+			 * lock to avoid other processes from seeing the allocated shared object and assuming it is
+			 * properly initialized when actually it is not. rtnobj_shm_free obtains the relinkrec->rtnobj_latch
+			 * which would fail an assert since we already hold that latch so add a dbg-flag to avoid an assert.
+			 */
+			rtnobj_shm_free(rhdr, LATCH_GRABBED_TRUE); /* Note: this will release relinkrec->rtnobj_latch for us */
+			return NULL;	/* caller will issue error */
+		}
+		rhdr = (rhdtyp *)objBuff;
+		codelen = rhdr->ptext_end_adr - rhdr->ptext_adr;	/* Length of object code */
+		assert(0 < codelen);
+		codeadr = objBuff + (UINTPTR_T)rhdr->ptext_adr;		/* Pointer to object code */
+		cacheflush(codeadr, codelen, BCACHE);			/* Cacheflush executable part from instruction cache */
+		RTNOBJ_DBG(fprintf(stderr, "rtnobj_shm_malloc : rtnname = %s : objhash = 0x%llx : "		\
+			"linkctl = 0x%llx : Inserted : refcnt = %d : elem = 0x%llx : numvers = %d\n",		\
+			relinkrec->rtnname_fixed.c, (long long unsigned int)objhash,				\
+			(long long unsigned int)linkctl, rtnobj->refcnt,					\
+			(long long unsigned int)objBuff, relinkrec->numvers);)
+		relinkrec->objhash = objhash;
+		++relinkrec->cycle;	/* cycle bump is because of the implicit ZRUPDATE that linking a routine does */
+		if (0 == relinkrec->cycle)
+			relinkrec->cycle = 1;	/* cycle value of 0 has special meaning, so bump to 1 in case we roll over */
+		zhent->cycle = relinkrec->cycle;	/* Update private cycle to be in sync with shared copy */
+		rel_latch(&relinkrec->rtnobj_latch);
+		return objBuff;
+	} while (TRUE);
+}
+
+void	rtnobj_shm_free(rhdtyp *rhead, boolean_t latch_grabbed)
+{
+	relinkrec_t		*relinkrec;
+	open_relinkctl_sgm	*linkctl;
+	relinkshm_hdr_t		*shm_hdr;
+	int			maxObjIndex, sizeIndex;
+	int			min_index, max_index, min_free_index, max_free_index, shm_index;
+	gtm_uint64_t		elemSize, origElemSize, objLen;
+	rtnobj_hdr_t		*rtnobj, *prev_rtnobj, *rtnobj2;
+	rtnobj_sm_off_t		shm_index_off;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	sm_uc_ptr_t		shm_base;
+	sm_off_t		shm_off, rtnobj_off;
+	que_ent_ptr_t		freeList;
+	zro_validation_entry	*zhent;
+	sm_uc_ptr_t		objBuff;
+	int			maxvers, curvers;
+	DEBUG_ONLY(size_t	shm_size;)
+	DEBUG_ONLY(int		dbg_shm_index;)
+#	ifdef DEBUG
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+#	endif
+	assert(rhead->shared_object);
+	assert(NULL != rhead->shared_ptext_adr);
+	if (NULL == rhead->shared_ptext_adr)
+		return;	/* in pro, be safe */
+	/* Note that if breakpoints are in effect, rhead->shared_ptext_adr will not be equal to rhead->ptext_adr.
+	 * This is because we would have taken a private copy of the code (for breakpoints) into ptext_adr and kept
+	 * shared_ptext_adr untouched. We will still need to free-up/decrement-refcnt the shared copy (shared_ptext_adr).
+	 */
+	objBuff = rhead->shared_ptext_adr - SIZEOF(rhdtyp);
+	rtnobj = (rtnobj_hdr_t *)(objBuff - OFFSETOF(rtnobj_hdr_t, userStorage));
+	assert(STATE_ALLOCATED == rtnobj->state);
+	assert(rtnobj->initialized);
+	assert(0 < rtnobj->refcnt);
+	assert(NULL != rhead->zhist);
+	zhent = rhead->zhist->end - 1;
+	relinkrec = zhent->relinkrec;
+	linkctl = zhent->relinkctl_bkptr;
+	assert(rhead->relinkctl_bkptr == linkctl);
+	shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+	assert(!linkctl->locked);
+	assert(!linkctl->hdr->file_deleted);
+	sizeIndex = rtnobj->queueIndex;
+#	ifdef DEBUG
+	/* Find shm_index corresponding to this routine buffer to cross check later */
+	min_index = linkctl->rtnobj_min_shm_index;
+	max_index = linkctl->rtnobj_max_shm_index;
+	for (dbg_shm_index = min_index; dbg_shm_index < max_index; dbg_shm_index++)
+	{
+		rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[dbg_shm_index];
+		if (INVALID_SHMID == rtnobj_shm_hdr->rtnobj_shmid)
+			continue;
+		shm_base = linkctl->rtnobj_shm_base[dbg_shm_index];
+		assert(NULL != shm_base);
+		shm_size = ((size_t)1 << (dbg_shm_index + MIN_RTNOBJ_SHM_INDEX));
+		if (((gtm_uint64_t)shm_base <= (gtm_uint64_t)rtnobj)
+				&& (((gtm_uint64_t)shm_base + shm_size) > (gtm_uint64_t)rtnobj))
+			break;	/* shared memory corresponding to rtnobj is found */
+	}
+	assert(dbg_shm_index < max_index);
+#	endif
+	if (!latch_grabbed && !grab_latch(&relinkrec->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC))
+	{
+		assert(FALSE);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+				ERR_RLNKRECLATCH, 3, relinkrec->rtnname_fixed.c, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+	}
+	assert(0 < rtnobj->refcnt);
+	assert(TREF(gtm_autorelink_keeprtn) || (REFCNT_INACCURATE != rtnobj->refcnt));
+	if (REFCNT_INACCURATE != rtnobj->refcnt)
+		rtnobj->refcnt--;	/* decrement refcnt while holding the rtnobj_lock */
+	if (rtnobj->refcnt)
+	{	/* The loaded object cannot be freed until refcnt becomes 0. But caller's job done. Return. */
+		RTNOBJ_DBG(fprintf(stderr,											\
+			"rtnobj_shm_free : rtnname = %s : objhash = 0x%llx : Decremented : refcnt = %d : elem = 0x%llx\n",	\
+			relinkrec->rtnname_fixed.c, (long long unsigned int)rtnobj->objhash, rtnobj->refcnt,			\
+			(long long unsigned int)objBuff);)
+		rel_latch(&relinkrec->rtnobj_latch);
+		return;
+	}
+	assert(sizeIndex == rtnobj->queueIndex); /* since this pid has not freed it yet, queueIndex must not change concurrently */
+	/* Note: Although we hold the rtnobj_latch, it is possible that new rtnobj_shmids get created concurrently
+	 * and an addition happens to the rtnobj->next_rtnobj_shm_offset linked list pointing to the new shmids.
+	 * But since additions to the linked list happen only at the end, we are guaranteed that the element of
+	 * interest (rtnobj which we want to free and have already located in rtnobj_shm_malloc) would be found
+	 * without reaching the tail portion of that linked list (which would require attaching to the new shmid).
+	 * So no concurrency issues to worry about like we had to in rtnobj_shm_malloc (see use of
+	 * SYNC_RTNOBJ_SHMID_CYCLE_IF_NEEDED macro and how it could do a "continue").
+	 */
+	shm_index_off = relinkrec->rtnobj_shm_offset;
+	prev_rtnobj = NULL;
+	maxvers = relinkrec->numvers;
+	curvers = 0;
+	while ((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off)
+	{
+		assertpro(maxvers >= curvers++);	/* assertpro to avoid infinite loops in PRO (just in case) */
+		shm_index = RTNOBJ_GET_SHM_INDEX(shm_index_off);
+		shm_off = RTNOBJ_GET_SHM_OFFSET(shm_index_off);
+		assert(0 == (shm_off % 8));
+		/* Since we hold the rtnobj_latch we should see valid values of shm_index/shm_off */
+		assert(min_index <= shm_index);
+		assert(max_index > shm_index);
+		assert(INVALID_SHMID != linkctl->rtnobj_shmid[shm_index]);
+		assert(shm_off < ((off_t)1 << (MIN_RTNOBJ_SHM_INDEX + shm_index)));
+		rtnobj2 = (rtnobj_hdr_t *)(linkctl->rtnobj_shm_base[shm_index] + shm_off);
+		if (rtnobj2 == rtnobj)
+			break;
+		prev_rtnobj = rtnobj2;
+		shm_index_off = rtnobj2->next_rtnobj_shm_offset;
+	}
+	assertpro((rtnobj_sm_off_t)NULL_RTNOBJ_SM_OFF_T != shm_index_off);
+	shm_index_off = rtnobj->next_rtnobj_shm_offset;
+	assert(dbg_shm_index == shm_index);
+	rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[shm_index];
+	shm_base = linkctl->rtnobj_shm_base[shm_index];
+	maxObjIndex = (shm_index + MIN_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SIZE_BITS);
+	assert(sizeIndex <= maxObjIndex);
+	elemSize = origElemSize = ((gtm_uint64_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS));
+	/* Now that we need to unload the object from shared memory, get a shared memory lock */
+	if (!grab_latch(&shm_hdr->relinkctl_latch, RLNKSHM_LATCH_TIMEOUT_SEC))
+	{
+		assert(FALSE);
+		rel_latch(&relinkrec->rtnobj_latch);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RLNKSHMLATCH, 2, RTS_ERROR_MSTR(&linkctl->zro_entry_name));
+	}
+	assert(rtnobj->objLen <= rtnobj_shm_hdr->real_len);
+	assert(elemSize <= rtnobj_shm_hdr->used_len);
+	objLen = rtnobj->objLen;
+	rtnobj_shm_hdr->real_len -= objLen;
+	rtnobj_shm_hdr->used_len -= elemSize;
+	/* Check if buddy of "rtnobj" is free and if so free the two together. Merge the two into a bigger chunk
+	 * and redo the free-buddy-check/merge as much as possible.
+	 */
+	min_free_index = rtnobj_shm_hdr->rtnobj_min_free_index;
+	if (sizeIndex < min_free_index)
+	{
+		min_free_index = sizeIndex;
+		rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex; /* we are about to do a insqt_rtnobj at freeList[sizeIndex] */
+	}
+	freeList = &rtnobj_shm_hdr->freeList[sizeIndex];
+	rtnobj_off = (sm_uc_ptr_t)rtnobj - shm_base;
+	while (sizeIndex < maxObjIndex)
+	{
+		rtnobj2 = (rtnobj_hdr_t *)(shm_base + (rtnobj_off ^ elemSize));	/* address of buddy */
+		assert(rtnobj2->queueIndex <= sizeIndex);
+		assert((STATE_ALLOCATED == rtnobj2->state) || (STATE_FREE == rtnobj2->state));
+		if (STATE_ALLOCATED == rtnobj2->state)
+			break;
+		if (rtnobj2->queueIndex != sizeIndex)
+			break;
+		remq_rtnobj_specific(freeList, shm_base, rtnobj2);
+		if ((NULL_RTNOBJ_SM_OFF_T == freeList->fl) && (sizeIndex == min_free_index))
+			min_free_index = NUM_RTNOBJ_SIZE_BITS;
+		if (rtnobj2 < rtnobj)
+		{
+			assert(elemSize == ((sm_off_t)rtnobj - (sm_off_t)rtnobj2));
+			rtnobj = rtnobj2;	/* Pick lower address buddy for top of new bigger block */
+			assert(rtnobj_off >= (sm_off_t)elemSize);
+			rtnobj_off -= elemSize;
+		}
+		freeList++;
+		sizeIndex++;
+		elemSize *= 2;
+	}
+	rtnobj->state = STATE_FREE;
+	rtnobj->queueIndex = sizeIndex;
+	assert(rtnobj_off == ((sm_uc_ptr_t)rtnobj - shm_base));
+	assert(0 == (rtnobj_off % ((sm_off_t)1 << (sizeIndex + MIN_RTNOBJ_SIZE_BITS))));
+	insqt_rtnobj(&rtnobj->userStorage.freePtr, freeList, shm_base);
+	max_free_index = rtnobj_shm_hdr->rtnobj_max_free_index;
+	if (sizeIndex >= max_free_index)
+		rtnobj_shm_hdr->rtnobj_max_free_index = sizeIndex + 1;	/* Recompute max_free_index */
+	if (NUM_RTNOBJ_SIZE_BITS == min_free_index)
+	{	/* Recompute min_free_index */
+		max_free_index = sizeIndex + 1;
+		sizeIndex = rtnobj_shm_hdr->rtnobj_min_free_index;
+		freeList = &rtnobj_shm_hdr->freeList[sizeIndex];
+		for ( ; sizeIndex < max_free_index; sizeIndex++, freeList++)
+		{
+			assert(sizeIndex < NUM_RTNOBJ_SIZE_BITS);
+			if (NULL_RTNOBJ_SM_OFF_T != freeList->fl)
+				break;
+		}
+		rtnobj_shm_hdr->rtnobj_min_free_index = sizeIndex;
+	}
+	DEBUG_ONLY(rtnobj_verify_min_max_free_index(rtnobj_shm_hdr));
+	DEBUG_ONLY(rtnobj_verify_freelist_fl_bl(rtnobj_shm_hdr, shm_base);)
+	rel_latch(&shm_hdr->relinkctl_latch);
+	if (NULL != prev_rtnobj)
+		prev_rtnobj->next_rtnobj_shm_offset = shm_index_off;
+	else
+		relinkrec->rtnobj_shm_offset = shm_index_off;
+	assert(objLen <= relinkrec->objLen);
+	relinkrec->objLen -= objLen;
+	assert(origElemSize <= relinkrec->usedLen);
+	relinkrec->usedLen -= origElemSize;
+	assert(0 < relinkrec->numvers);
+	relinkrec->numvers--;
+	RTNOBJ_DBG(fprintf(stderr,												\
+		"rtnobj_shm_free : rtnname = %s : objhash = 0x%llx : Freed : refcnt = %d : elem = 0x%llx : numvers = %d\n",	\
+		relinkrec->rtnname_fixed.c, (long long unsigned int)rtnobj->objhash, rtnobj->refcnt,				\
+		(long long unsigned int)objBuff, relinkrec->numvers);)
+	rel_latch(&relinkrec->rtnobj_latch);
+	return;
+}
+#endif
diff --git a/sr_unix/rtnobj.h b/sr_unix/rtnobj.h
new file mode 100644
index 0000000..71dc1cd
--- /dev/null
+++ b/sr_unix/rtnobj.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), 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 RTNOBJ_H_INCLUDED
+#define RTNOBJ_H_INCLUDED
+
+#ifdef AUTORELINK_SUPPORTED
+
+#include <rtnhdr.h>
+
+#define	LATCH_GRABBED_FALSE	FALSE
+#define	LATCH_GRABBED_TRUE	TRUE
+
+#ifdef DEBUG
+void	rtnobj_verify_freelist_fl_bl(rtnobjshm_hdr_t *rtnobj_shm_hdr, sm_uc_ptr_t shm_base);
+void	rtnobj_verify_min_max_free_index(rtnobjshm_hdr_t *rtnobj_shm_hdr);
+#endif
+void		insqt_rtnobj(que_ent_ptr_t new, que_ent_ptr_t que_base, sm_uc_ptr_t shm_base);
+rtnobj_hdr_t	*remqh_rtnobj(que_ent_ptr_t base, sm_uc_ptr_t shm_base);
+void		remq_rtnobj_specific(que_ent_ptr_t que_base, sm_uc_ptr_t shm_base, rtnobj_hdr_t *rtnobj);
+sm_uc_ptr_t	rtnobj_shm_malloc(zro_hist *zhist, int fd, off_t obj_size, gtm_uint64_t objhash);
+void		rtnobj_shm_free(rhdtyp *rhead, boolean_t latch_grabbed);
+
+#endif
+
+#endif /* RTNOBJ_H_INCLUDED */
diff --git a/sr_unix/runall.csh b/sr_unix/runall.csh
index 712e2c1..1772fd8 100644
--- a/sr_unix/runall.csh
+++ b/sr_unix/runall.csh
@@ -260,7 +260,7 @@ else
 		echo "...... Searching for --------> out-of-date PCT ROUTINEs ...... "
 		pushd $gtm_pct >& /dev/null
 		ln -s $gtm_exe/${latest_exe_with_rel_path} __temp_runall_${latest_exe}
-		ls -1Lat | sed -n '1,/__temp_runall_'${latest_exe}'/p' | grep -E '\.m$' >>&! ${TMP_DIR}_pct_files
+		ls -1Lat | sed -n '1,/__temp_runall_'${latest_exe}'/p' | grep -E '\.(m|hlp)$' >>&! ${TMP_DIR}_pct_files
 		rm -f __temp_runall_${latest_exe} >& /dev/null
 		popd >& /dev/null
 	else
@@ -571,6 +571,13 @@ else
 	if (0 != $status) @ runall_status = $status
 endif
 
+# Create the GT.M/GDE/MUPIP/DSE/LKE help databases
+$gtm_tools/generate_help.csh $gtm_pct $gtm_log/error.${RUNALL_IMAGE}.log
+if ($status) then
+	@ runall_status++
+	echo "runall-E-hlp, Error generating hlp databases"
+endif
+
 echo ""
 if ( -f $gtm_log/error.${RUNALL_IMAGE}.log ) then
 	echo "Error summary:"
diff --git a/sr_unix/secshr_client.c b/sr_unix/secshr_client.c
index 516f1e0..fddf7fd 100644
--- a/sr_unix/secshr_client.c
+++ b/sr_unix/secshr_client.c
@@ -19,6 +19,7 @@
 #include <sys/sem.h>
 #include <sys/shm.h>
 #include <sys/param.h>
+
 #include "gtm_ctype.h"
 #include "gtm_stdlib.h"		/* for exit() */
 #include "gtm_string.h"
@@ -27,10 +28,11 @@
 #include "gtm_unistd.h"
 #include "gtm_stdio.h"
 #include "gtm_stat.h"
-#include "gt_timer.h"
 #include "gtm_limits.h"
 #include "gtm_syslog.h"
+#include "gtm_ipc.h"
 
+#include "gt_timer.h"
 #include "gtmio.h"
 #include "io.h"
 #include "gtmsecshr.h"
@@ -52,9 +54,9 @@
 #include "filestruct.h"
 #include "gtm_logicals.h"
 #include "secshr_client.h"
-#include "gtm_semutils.h"
 #include "hashtab.h"		/* for STR_HASH macro */
 #include "fork_init.h"
+#include "wbox_test_init.h"
 
 GBLREF struct sockaddr_un       gtmsecshr_sock_name;
 GBLREF key_t                    gtmsecshr_key;
@@ -92,7 +94,7 @@ const static char readonly *secshrstart_error_code[] = {
 	"",
 	"gtmsecshr unable to set-uid to root",
 	"The environmental variable gtm_dist is pointing to an invalid path",
-	"Unable to exec gtmsecshr",
+	"Unable to start gtmsecshr executable",
 	"gtmsecshr unable to create a  child process",
 	"Error with gtmsecshr semaphore",
 	"gtmsecshr already running - invalid invocation",
@@ -210,8 +212,9 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
 		if (-1 == Stat(gtmsecshr_pathname.addr, &stat_buf))
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
 					LEN_AND_LIT("stat"), CALLFROM, errno);
-		if ((ROOTUID != stat_buf.st_uid) ||
-		    !(stat_buf.st_mode & S_ISUID))
+		if ((ROOTUID != stat_buf.st_uid)
+			|| !(stat_buf.st_mode & S_ISUID)
+			|| (0 != ACCESS(gtmsecshr_pathname.addr, (X_OK))))
 			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRPERM);
 		gtmsecshr_file_check_done = TRUE;
 	}
@@ -442,12 +445,14 @@ int create_server(void)
 	{
 		process_id = getpid();
 		/* Do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */
+		if (WBTEST_ENABLED(WBTEST_BADEXEC_SECSHR_PROCESS))
+			STRCPY(gtmsecshr_path, "");
 		status = EXECL(gtmsecshr_path, gtmsecshr_path, 0);
 		if (-1 == status)
 		{
-                        send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
-				 ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
-			exit(UNABLETOEXECGTMSECSHR);
+			send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
+				ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[UNABLETOEXECGTMSECSHR]));
+			_exit(UNABLETOEXECGTMSECSHR);
 		}
         } else
 	{
diff --git a/sr_unix/sleep.c b/sr_unix/sleep.c
index 5372e72..5ca33da 100644
--- a/sr_unix/sleep.c
+++ b/sr_unix/sleep.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2002 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -10,61 +10,17 @@
  ****************************************************************/
 
 #include "mdef.h"
-#include <time.h>
+#include "gtm_time.h"
+#include <sys/time.h>
+#include <errno.h>
 #include "sleep.h"
 
-#ifndef __MVS__
-
-int m_sleep(int seconds)
-{
-    m_time_t rqtp, rmtp;
-
-    rqtp.tv_sec=seconds;
-    rqtp.tv_nsec=0;
-
-    return nanosleep_func(&rqtp,&rmtp);
-}
-
-int m_usleep(int useconds)
-{
-    m_time_t rqtp, rmtp;
-
-    rqtp.tv_sec=0;
-    rqtp.tv_nsec=useconds*1000;
-
-    return nanosleep_func(&rqtp,&rmtp);
-}
-
-int m_nsleep(int nseconds)
-{
-    m_time_t rqtp, rmtp;
-
-    rqtp.tv_sec=0;
-    rqtp.tv_nsec=nseconds;
-
-    return nanosleep_func(&rqtp,&rmtp);
-}
-
-#else
-
-/* OS390 versions must use usleep, which doesn't use m_time_t struct */
-
-#include "gtm_unistd.h"
-
-int m_sleep(int seconds)
-{
-    return nanosleep_func((useconds_t)(1000 * seconds));
-}
-
-int m_usleep(int useconds)
-{
-    return nanosleep_func((useconds_t)useconds);
-}
+#ifdef __MVS__
+/* OS390 versions must use usleep */
+#  include "gtm_unistd.h"
+#endif
 
-/* Note: this functions is not called by anyone */
-int m_nsleep(int nseconds)	/* On OS390, this will sleep for one microsecond */
+void m_usleep(int useconds)
 {
-    return nanosleep_func((useconds_t)1);
+	SLEEP_USEC(useconds, FALSE);
 }
-
-#endif
diff --git a/sr_unix/sleep.h b/sr_unix/sleep.h
index e6ec0b3..775db8d 100644
--- a/sr_unix/sleep.h
+++ b/sr_unix/sleep.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -18,11 +18,7 @@
  * through the LONG_SLEEP macro defined in mdef.h.
  */
 
-int m_sleep(int seconds);
-int m_usleep(int useconds);
-int m_nsleep(int nseconds);
-
-#ifdef UNIX
+void m_usleep(int useconds);
 
 # if !defined(_AIX) && !defined(__osf__) && !defined(__hpux) && !defined(__sparc) && !defined(_UWIN) && !defined(__linux__)
 #   if !defined(__MVS__) && !defined(__CYGWIN__)
@@ -33,156 +29,109 @@ int m_nsleep(int nseconds);
 #define E_6	1000000
 #define E_9	1000000000
 
-#define SET_EXPIR_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS)						\
-{													\
-	gettimeofday(&(NOW_TIMEVAL), NULL);								\
-	if (E_6 <= ((NOW_TIMEVAL).tv_usec + USECS))							\
-	{												\
-		(EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS) + 1;				\
-		(EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS) - E_6;			\
-	} else												\
-	{												\
-		(EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS);					\
-		(EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS);				\
-	}												\
-}
-
-#define EVAL_REM_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS)						\
-{													\
-	gettimeofday(&(NOW_TIMEVAL), NULL);								\
-	if (((NOW_TIMEVAL).tv_sec > (EXPIR_TIMEVAL).tv_sec)						\
-		|| (((NOW_TIMEVAL).tv_sec == (EXPIR_TIMEVAL).tv_sec)					\
-			&& ((NOW_TIMEVAL).tv_usec >= (EXPIR_TIMEVAL).tv_usec)))				\
-		return;											\
-	if ((EXPIR_TIMEVAL).tv_usec < (NOW_TIMEVAL).tv_usec)						\
-	{												\
-		SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec - 1);			\
-		USECS = (int)(E_6 + (EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec);			\
-	} else												\
-	{												\
-		SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec);				\
-		USECS = (int)((EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec);				\
-	}												\
-}
-
-#if defined(__osf__) || defined(__hpux)
-/* The above platforms do not support clock_nanosleep, so use nanosleep. To avoid sleeping for much
- * longer than requested in case of pathologically many interrupts, recalculate the remaining duration
- * with gettimeofday.
+#define SET_EXPIR_TIME(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS)				\
+MBSTART {										\
+	gettimeofday(&(NOW_TIMEVAL), NULL);						\
+	if (E_6 <= ((NOW_TIMEVAL).tv_usec + USECS))					\
+	{										\
+		(EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS) + 1;		\
+		(EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS) - E_6;	\
+	} else										\
+	{										\
+		(EXPIR_TIMEVAL).tv_sec = (NOW_TIMEVAL).tv_sec + (SECS);			\
+		(EXPIR_TIMEVAL).tv_usec = (NOW_TIMEVAL).tv_usec + (USECS);		\
+	}										\
+} MBEND
+
+/* This macro *does not* have surrounding braces and *will break* out of the block it is in on non-positive remaining time. */
+#define UPDATE_REM_TIME_OR_BREAK(NOW_TIMEVAL, EXPIR_TIMEVAL, SECS, USECS)		\
+	gettimeofday(&(NOW_TIMEVAL), NULL);						\
+	if (((NOW_TIMEVAL).tv_sec > (EXPIR_TIMEVAL).tv_sec)				\
+		|| (((NOW_TIMEVAL).tv_sec == (EXPIR_TIMEVAL).tv_sec)			\
+			&& ((NOW_TIMEVAL).tv_usec >= (EXPIR_TIMEVAL).tv_usec)))		\
+		break;									\
+	if ((EXPIR_TIMEVAL).tv_usec < (NOW_TIMEVAL).tv_usec)				\
+	{										\
+		SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec - 1);	\
+		USECS = (int)(E_6 + (EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec);	\
+	} else										\
+	{										\
+		SECS = (time_t)((EXPIR_TIMEVAL).tv_sec - (NOW_TIMEVAL).tv_sec);		\
+		USECS = (int)((EXPIR_TIMEVAL).tv_usec - (NOW_TIMEVAL).tv_usec);		\
+	}										\
+
+#ifdef __MVS__
+/* On z/OS neither clock_nanosleep nor nanosleep is available, so use a combination of sleep, usleep, and gettimeofday instead.
+ * Since we do not have a z/OS box presently, this implementation has not been tested, and so it likely needs some casts at the very
+ * least. Another note is that sleep is unsafe to mix with timers on other platforms, but on z/OS the documentation does not mention
+ * any fallouts, so this should be verified. If it turns out that sleep is unsafe, we might have to use pthread_cond_timewait or
+ * call usleep (which, given that we have used it on z/OS before, should be safe) in a loop.
  */
-#  define NANOSLEEP(MS)											\
-{													\
-	int 		status, usecs;									\
-	struct timespec	req;										\
-	struct timeval	now, expir;									\
-													\
-	assert(0 < MS);											\
-	req.tv_sec = (time_t)(MS / 1000);								\
-	usecs = (MS % 1000) * 1000;									\
-	req.tv_nsec = (long)(usecs * 1000);								\
-	assert(E_9 > req.tv_nsec);									\
-	SET_EXPIR_TIME(now, expir, req.tv_sec, usecs)							\
-	while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno))				\
-	{												\
-		EVAL_REM_TIME(now, expir, req.tv_sec, usecs);						\
-		req.tv_nsec = (long)(usecs * 1000);							\
-	}												\
-}
-#elif defined(__MVS__)
-/* On z/OS neither clock_nanosleep nor nanosleep is available, so use a combination of sleep, usleep,
- * and gettimeofday instead. Since we do not have a z/OS box presently, this implementation has not
- * been tested, and so it likely needs some casts at the very least. Another note is that sleep is
- * unsafe to mix with timers on other platforms, but on z/OS the documentation does not mention any
- * fallouts, so this should be verified. If it turns out that sleep is unsafe, we might have to use
- * pthread_cond_timewait or call usleep (which, given that we have used it on z/OS before, should be
- * safe) in a loop.
- */
-#  define NANOSLEEP(MS)											\
-{													\
-	int 		secs;										\
-	useconds_t	usecs;										\
-	struct timeval	now, expir;									\
-													\
-	assert(0 < MS);											\
-	secs = MS / 1000;										\
-	usecs = MS % 1000;										\
-	SET_EXPIR_TIME(now, expir, secs, usecs)								\
-	while (0 < secs)										\
-	{												\
-		sleep(secs);	/* BYPASSOK:  */							\
-		EVAL_REM_TIME(now, expir, secs, usecs);							\
-	}												\
-	while (0 < usecs)										\
-	{												\
-		usleep(usecs);										\
-		EVAL_REM_TIME(now, expir, secs, usecs);							\
-	}												\
-}
+#  define SLEEP_USEC(MICROSECONDS, RESTART)						\
+MBSTART {										\
+	int 		secs, interrupted;						\
+	useconds_t	usecs;								\
+	struct timeval	now, expir;							\
+											\
+	assert(0 < MICROSECONDS);							\
+	secs = (MICROSECONDS) / 1000;							\
+	usecs = (MICROSECONDS) % E_6;							\
+	SET_EXPIR_TIME(now, expir, secs, usecs);					\
+	if (RESTART)									\
+	{										\
+		while (0 < secs)							\
+		{									\
+			sleep(secs);		/* BYPASSOK */				\
+			/* This macro will break the loop when it is time. */		\
+			UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs);		\
+		}									\
+		while (0 < usecs)							\
+		{									\
+			usleep(usecs);							\
+			/* This macro will break the loop when it is time. */		\
+			UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs);		\
+		}									\
+	} else										\
+	{										\
+		interrupted = sleep(secs);	/* BYPASSOK */				\
+		if (!interrupted)							\
+		{	/* This macro will break the loop when it is time. */		\
+			UPDATE_REM_TIME_OR_BREAK(now, expir, secs, usecs);		\
+			usleep(usecs);							\
+		}									\
+	}										\
+} MBEND
 #else
-/* The major supported platforms should have clock_nanosleep implementation, so to avoid extending the
- * actual sleep times, we use clock_gettime to first obtain the point of reference, and then specify
- * the TIMER_ABSTIME flag when invoking clock_nanosleep for absolute offsets. In case CLOCK_REALTIME
- * type of clock is not supported on some platform, we fall back on nanosleep.
+/* On most UNIX platforms a combination of nanosleep() and gettimeofday() proved to be the most supported, accurate, and
+ * operationally sound approach. Alternatives for implementing high-resolution sleeps include clock_nanosleep() and nsleep()
+ * (AIX only); however, neither of those provide better accuracy or speed. Additionally, the clock_gettime() function does not
+ * prove to be any faster than gettimeofday(), and since we do not (yet) operate at sub-millisecond levels, it is not utilized.
+ *
+ * On Linux boxes be sure to define USER_HZ macro (in gt_timers.c) appropriately to mitigate the timer clustering imposed by
+ * the OS. Historically, the USER_HZ value has defaulted to 100 (same as HZ), thus resulting in at most 10ms accuracy when
+ * delivering timed events.
  */
-#  define NANOSLEEP(MS)											\
-{													\
-	int 		status, usecs;									\
-	struct timespec	req, cur;									\
-	struct timeval	now, expir;									\
-													\
-	req.tv_sec = (time_t)(MS / 1000);								\
-	usecs = (MS % 1000) * 1000;									\
-	req.tv_nsec = (long)(usecs * 1000);								\
-	assert(E_9 > req.tv_nsec);									\
-	if ((-1 == (status = clock_gettime(CLOCK_REALTIME, &cur))) && (EINVAL == errno))		\
-	{												\
-		SET_EXPIR_TIME(now, expir, req.tv_sec, usecs)						\
-		while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno))			\
-		{											\
-			EVAL_REM_TIME(now, expir, req.tv_sec, usecs);					\
-			req.tv_nsec = (long)(usecs * 1000);						\
-		}											\
-	} else												\
-	{												\
-		if (E_9 <= cur.tv_nsec + req.tv_nsec)							\
-		{											\
-			req.tv_sec += (cur.tv_sec + 1);							\
-			req.tv_nsec = cur.tv_nsec + req.tv_nsec - E_9;					\
-		} else											\
-		{											\
-			req.tv_sec += cur.tv_sec;							\
-			req.tv_nsec += cur.tv_nsec;							\
-		}											\
-		while ((-1 == (status = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &req, NULL)))	\
-			&& (EINTR == errno));								\
-	}												\
-}
-#endif
-
-# ifdef _AIX
-   typedef struct timestruc_t m_time_t;
-#  define nanosleep_func nsleep
-# endif
-
-# if defined(__sparc) || defined(__hpux) || defined(__osf__) || defined (__linux__) || defined (__CYGWIN__)
-   typedef struct timespec m_time_t;
-#  define nanosleep_func nanosleep
-# endif
-
-# ifdef _UWIN
-# include "gtm_select.h"
-# define usleep_func gtm_usleep
-# endif
-
-# ifdef __MVS__
-   typedef struct timespec m_time_t;
-#  define nanosleep_func usleep			/* m_nsleep will not work on OS390, but it is not used */
-# endif
-
-#else
-
-# error  "Unsure of support for sleep functions on this non-UNIX platform"
-
+#  define SLEEP_USEC(MICROSECONDS, RESTART)						\
+MBSTART {										\
+	int 		status, usecs;							\
+	struct timespec	req;								\
+	struct timeval	now, expir;							\
+											\
+	assert(0 < MICROSECONDS);							\
+	req.tv_sec = (time_t)((MICROSECONDS) / E_6);					\
+	req.tv_nsec = (long)((usecs = (MICROSECONDS) % E_6) * 1000); /* Assignment! */	\
+	assert(E_9 > req.tv_nsec);							\
+	if (RESTART)									\
+	{										\
+		SET_EXPIR_TIME(now, expir, req.tv_sec, usecs);				\
+		while ((-1 == (status = nanosleep(&req, NULL))) && (EINTR == errno))	\
+		{	/* This macro will break the loop when it is time. */		\
+			UPDATE_REM_TIME_OR_BREAK(now, expir, req.tv_sec, usecs);	\
+			req.tv_nsec = (long)(usecs * 1000);				\
+		}									\
+	} else										\
+		nanosleep(&req, NULL);							\
+} MBEND
 #endif
 
 #endif /* SLEEP_H */
diff --git a/sr_unix/ss_context_mgr.c b/sr_unix/ss_context_mgr.c
index 9dc425f..de62378 100644
--- a/sr_unix/ss_context_mgr.c
+++ b/sr_unix/ss_context_mgr.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2009, 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2009, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -21,6 +21,9 @@
 #include "gtm_stdlib.h"
 #include "gtm_tempnam.h"
 #include "gtm_time.h"
+#ifdef DEBUG
+#include "gtm_ipc.h"
+#endif
 
 #include "gdsroot.h"
 #include "gdskill.h"
@@ -64,6 +67,8 @@ GBLREF	sgmnt_addrs		*cs_addrs;
 GBLREF	enum gtmImageTypes	image_type;
 GBLREF	uint4			process_id;
 
+error_def(ERR_SYSCALL);
+
 boolean_t	ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
 {
 	shm_snapshot_ptr_t		ss_shm_ptr;
@@ -73,7 +78,6 @@ boolean_t	ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
 	void				*ss_shmaddr;
 	ZOS_ONLY(int			realfiletag;)
 
-	error_def(ERR_SYSCALL);
 	ZOS_ONLY(error_def(ERR_BADTAG);)
 	ZOS_ONLY(error_def(ERR_TEXT);)
 
@@ -107,7 +111,7 @@ boolean_t	ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
 			/* It's possible that by the time we attach to the shared memory, the identifier has been removed from the
 			 * system by INTEG which completed it's processing.
 			 */
-			assert((EIDRM == status) || (EINVAL == status));
+			assert(SHM_REMOVED(status));
 			assert(INVALID_SHMID == lcl_ss_ctx->attach_shmid);
 			lcl_ss_ctx->cur_state = SNAPSHOT_SHM_ATTACH_FAIL;
 			lcl_ss_ctx->failure_errno = status;
@@ -135,7 +139,7 @@ boolean_t	ss_create_context(snapshot_context_ptr_t lcl_ss_ctx, int ss_shmcycle)
 		{
 			status = errno;
 			assert(FALSE);
-			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
 		}
 		lcl_ss_ctx->attach_shmid = lcl_ss_ctx->nl_shmid = INVALID_SHMID; /* reset shmid since we failed */
 		lcl_ss_ctx->cur_state = SHADOW_FIL_OPEN_FAIL;
@@ -154,8 +158,6 @@ boolean_t	ss_destroy_context(snapshot_context_ptr_t lcl_ss_ctx)
 {
 	int				status;
 
-	error_def(ERR_SYSCALL);
-
 	assert(NULL != lcl_ss_ctx);
 	if (FD_INVALID != lcl_ss_ctx->shdw_fd)
 	{
@@ -167,7 +169,7 @@ boolean_t	ss_destroy_context(snapshot_context_ptr_t lcl_ss_ctx)
 		{
 			status = errno;
 			assert(FALSE);
-			rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("Error with shmdt"), CALLFROM, status);
 		}
 	}
 	/* Invalidate the context */
diff --git a/sr_unix/tab_probecrit_rec.h b/sr_unix/tab_probecrit_rec.h
new file mode 100644
index 0000000..60db612
--- /dev/null
+++ b/sr_unix/tab_probecrit_rec.h
@@ -0,0 +1,23 @@
+/****************************************************************
+ *								*
+ *	Copyright 2008, 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), 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 that each TAB_PROBECRIT_REC entry corresponds to a field in cs_addrs
+ * Therefore, avoid any operation that changes the offset of any of these entries in the cs_addrs.
+ * Additions are to be done at the END of the structures.
+ * Replacing existing fields with new fields is allowed (provided their implications are thoroughly analyzed).
+ */
+TAB_PROBECRIT_REC(t_get_crit          , "CPT", "nanoseconds for the probe to get crit       ")
+TAB_PROBECRIT_REC(p_crit_failed       , "CFN", "# of failures of the probe to get crit      ")
+TAB_PROBECRIT_REC(p_crit_que_slps     , "CQN", "# of queue sleeps by the probe              ")
+TAB_PROBECRIT_REC(p_crit_yields       , "CYN", "# of process yields by the probe            ")
+TAB_PROBECRIT_REC(p_crit_que_full     , "CQF", "# of queue fulls encountered by the probe   ")
+TAB_PROBECRIT_REC(p_crit_que_slots    , "CQE", "# of empty queue slots found by the probe   ")
+TAB_PROBECRIT_REC(p_crit_success      , "CAT", "# of crit acquired total successes          ")
diff --git a/sr_unix/trigger.h b/sr_unix/trigger.h
index ba431ab..27b1e1a 100644
--- a/sr_unix/trigger.h
+++ b/sr_unix/trigger.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -13,22 +13,26 @@
 #define MUPIP_TRIGGER_INCLUDED
 
 /* The order of these must match trigger_subs defined in mtables.c */
-#define TRIGGER_SUBDEF(SUBNAME) SUBNAME##_SUB
 typedef enum
 {
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	SUBSTYPE,
 #include "trigger_subs_def.h"
-#undef TRIGGER_SUBDEF
-	,NUM_TOTAL_SUBS
+#undef TRIGGER_SUBSDEF
+	NUM_TOTAL_SUBS
 } trig_subs_t;
-#define NUM_SUBS		NUM_TOTAL_SUBS - 2	/* Number of subscripts users deal with - hash values not included */
-
+#define NUM_SUBS		NUM_TOTAL_SUBS - 2	/* Number of subscripts users deal with.
+							 * Hash related subscripts BHASH/LHASH not included.
+							 * This assumes BHASH and LHASH are last two entires and is asserted
+							 * in "trigger_delete"/"write_out_trigger"/"trigger_update" function entry.
+							 */
 typedef enum
 {
 	STATS_ADDED = 0,
 	STATS_DELETED,
-	STATS_UNCHANGED,
 	STATS_MODIFIED,
-	STATS_ERROR,
+	STATS_ERROR_TRIGFILE,
+	STATS_UNCHANGED_TRIGFILE,
+	STATS_NOERROR_TRIGFILE,
 	NUM_STATS
 } trig_stats_t;
 
@@ -52,16 +56,15 @@ typedef enum
 #define MAX_USER_TRIGNAME_LEN	MAX_MIDENT_LEN - 3	/* 3 -- 2 for run time chars and 1 for delimiter */
 #define	MAX_AUTO_TRIGNAME_LEN	(MAX_MIDENT_LEN - 4 - NUM_TRIGNAME_SEQ_CHARS)	/* 4 -- 2 for runtime characters, 2 for delims */
 
-#define LITERAL_BHASH		"BHASH"
-#define LITERAL_LHASH		"LHASH"
 #define LITERAL_MAXHASHVAL	"$"				/* '$' collates between '#' and '%' */
 #define LITERAL_HASHSEQNUM	"#SEQNUM"
 #define	LITERAL_HASHTNAME	"#TNAME"
 #define	LITERAL_HASHTNCOUNT	"#TNCOUNT"
 #define	LITERAL_HASHTRHASH	"#TRHASH"
 
-#define LITERAL_BHASH_LEN	STR_LIT_LEN(LITERAL_BHASH)
-#define LITERAL_LHASH_LEN	STR_LIT_LEN(LITERAL_LHASH)
+#define	TRSBS_IN_NONE		0
+#define	TRSBS_IN_BHASH		1
+#define	TRSBS_IN_LHASH		2
 
 #define	INITIAL_CYCLE		"1"
 
@@ -70,18 +73,17 @@ typedef enum
 #define XTENDED_START_LEN	STR_LIT_LEN(XTENDED_START)
 #define XTENDED_STOP_LEN	STR_LIT_LEN(XTENDED_STOP)
 
-#define	CMDS_PRESENT		0
-#define	OPTIONS_PRESENT		0
-#define	OPTION_CONFLICT		0
-#define	NO_NAME_CHANGE		0
 #define	PUT_SUCCESS		0
-#define	SEQ_SUCCESS		0
-#define	ADD_NEW_TRIGGER		-1
-#define	INVALID_LABEL		-2
-#define	K_ZTK_CONFLICT		-3
-#define	VAL_TOO_LONG		-4
-#define	KEY_TOO_LONG		-5
-#define	TOO_MANY_TRIGGERS	-6
+
+#define	INVALID_LABEL			-1
+#define	K_ZTK_CONFLICT			-2
+#define	VAL_TOO_LONG			-3
+#define	KEY_TOO_LONG			-4
+#define	TOO_MANY_TRIGGERS		-5
+#define	ADD_SET_MODIFY_KILL_TRIG	-6
+#define	ADD_SET_NOCHNG_KILL_TRIG	-7
+#define	OPTIONS_CMDS_CONFLICT		-8
+#define	NAME_CMDS_CONFLICT		-9
 
 #define CONV_TO_ZWR(LEN, PTR, OUT_LEN, OUT_STR)						\
 {											\
@@ -226,6 +228,27 @@ typedef enum
 	TREF(gv_some_subsc_null) = was_null;							\
 }
 
+#define	BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(TRIG_VAL, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3) 	\
+{												\
+	boolean_t		was_null = FALSE, is_null = FALSE;				\
+	mval			*subsc_ptr;							\
+	DCL_THREADGBL_ACCESS;									\
+												\
+	SETUP_THREADGBL_ACCESS;									\
+	BUILD_HASHT_CURRKEY_NAME;								\
+	subsc_ptr = &TRIG_VAL;									\
+	STR2MVAL(TRIG_VAL, SUB0, LEN0);								\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);	\
+	STR2MVAL(TRIG_VAL, SUB1, LEN1);								\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);	\
+	subsc_ptr = &SUB2;									\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);	\
+	subsc_ptr = &SUB3;									\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);	\
+	TREF(gv_last_subsc_null) = is_null;							\
+	TREF(gv_some_subsc_null) = was_null;							\
+}
+
 #define BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(TRIG_VAL, SUB1, LEN1, SUB2, SUB3, LEN3)		\
 {												\
 	boolean_t		was_null = FALSE, is_null = FALSE;				\
@@ -246,6 +269,28 @@ typedef enum
 	TREF(gv_some_subsc_null) = was_null;							\
 }
 
+#define BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY_T(TRIG_VAL, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3)	\
+{													\
+	boolean_t		was_null = FALSE, is_null = FALSE;					\
+	mval			*subsc_ptr;								\
+	DCL_THREADGBL_ACCESS;										\
+													\
+	SETUP_THREADGBL_ACCESS;										\
+	BUILD_HASHT_CURRKEY_NAME;									\
+	subsc_ptr = &TRIG_VAL;										\
+	STR2MVAL(TRIG_VAL, SUB0, LEN0);									\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);		\
+	STR2MVAL(TRIG_VAL, SUB1, LEN1);									\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);		\
+	subsc_ptr = &SUB2;										\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);		\
+	subsc_ptr = &TRIG_VAL;										\
+	STR2MVAL(TRIG_VAL, SUB3, LEN3);									\
+	COPY_SUBS_TO_GVCURRKEY(subsc_ptr, gv_cur_region, gv_currkey, was_null, is_null);		\
+	TREF(gv_last_subsc_null) = is_null;								\
+	TREF(gv_some_subsc_null) = was_null;								\
+}
+
 #define	BUILD_HASHT_SUB_SUB_SUB_CURRKEY_T(TRIG_VAL, SUB1, LEN1, SUB2, LEN2, SUB3, LEN3) 	\
 {												\
 	boolean_t		was_null = FALSE, is_null = FALSE;				\
@@ -288,35 +333,35 @@ typedef enum
 	TREF(gv_some_subsc_null) = was_null;							\
 }
 
-#define	TRIGGER_GLOBAL_ASSIGNMENT_STR(TRIG_VAL, VALUE, LEN, RES)					\
-{													\
-	STR2MVAL(trig_val, VALUE, LEN);									\
-	if (gv_currkey->end + 1 + TRIG_VAL.str.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size)	\
-		RES = VAL_TOO_LONG;									\
-	else if (gv_currkey->end + 1 > gv_cur_region->max_key_size)					\
-		RES = KEY_TOO_LONG;									\
-	else												\
-	{												\
-		gvcst_put(&TRIG_VAL);									\
-		RES = PUT_SUCCESS;									\
-	}												\
-}
-
-#define	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(TRIG_VAL, VALUE, RES)						\
-{													\
-	mval		*lcl_mv_ptr;									\
-													\
-	lcl_mv_ptr = &VALUE;										\
-	MV_FORCE_STR(lcl_mv_ptr);									\
-	if (gv_currkey->end + 1 + TRIG_VAL.str.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size)	\
-		RES = VAL_TOO_LONG;									\
-	else if (gv_currkey->end + 1 > gv_cur_region->max_key_size)					\
-		RES = KEY_TOO_LONG;									\
-	else												\
-	{												\
-		gvcst_put(lcl_mv_ptr);									\
-		RES = PUT_SUCCESS;									\
-	}												\
+#define	TRIGGER_GLOBAL_ASSIGNMENT_STR(TRIG_VAL, VALUE, LEN, RES)	\
+{									\
+	STR2MVAL(TRIG_VAL, VALUE, LEN);					\
+	if (LEN > gv_cur_region->max_rec_size)				\
+		RES = VAL_TOO_LONG;					\
+	else if (gv_currkey->end + 1 > gv_cur_region->max_key_size)	\
+		RES = KEY_TOO_LONG;					\
+	else								\
+	{								\
+		gvcst_put(&TRIG_VAL);					\
+		RES = PUT_SUCCESS;					\
+	}								\
+}
+
+#define	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES)			\
+{									\
+	mval		*lcl_mv_ptr;					\
+									\
+	lcl_mv_ptr = &VALUE;						\
+	MV_FORCE_STR(lcl_mv_ptr);					\
+	if (lcl_mv_ptr->str.len > gv_cur_region->max_rec_size)		\
+		RES = VAL_TOO_LONG;					\
+	else if (gv_currkey->end + 1 > gv_cur_region->max_key_size)	\
+		RES = KEY_TOO_LONG;					\
+	else								\
+	{								\
+		gvcst_put(lcl_mv_ptr);					\
+		RES = PUT_SUCCESS;					\
+	}								\
 }
 
 #define BUILD_HASHT_SUB_CURRKEY(SUB, LEN)								\
@@ -354,6 +399,20 @@ typedef enum
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3);			\
 }
 
+#define BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3)			\
+{													\
+	mval			trig_val;								\
+													\
+	BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, LEN3);	\
+}
+
+#define BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3)			\
+{													\
+	mval			trig_val;								\
+													\
+	BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3);		\
+}
+
 #define	BUILD_HASHT_SUB_SUB_SUB_CURRKEY(SUB1, LEN1, SUB2, LEN2, SUB3, LEN3)				\
 {													\
 	mval			trig_val;								\
@@ -384,12 +443,20 @@ typedef enum
 	TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES);					\
 }
 
+#define	SET_TRIGGER_GLOBAL_SUB_MVAL(SUB1, LEN1, VALUE, RES)						\
+{													\
+	mval			trig_val;								\
+													\
+	BUILD_HASHT_SUB_CURRKEY_T(trig_val, SUB1, LEN1);						\
+	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES);							\
+}
+
 #define	SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(SUB1, LEN1, SUB2, LEN2, VALUE, RES)				\
 {													\
 	mval			trig_val;								\
 													\
 	BUILD_HASHT_SUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, LEN2);				\
-	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES);						\
+	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES);							\
 }
 
 #define	SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(SUB1, LEN1, SUB2, SUB3, LEN3, VALUE, LEN, RES)		\
@@ -404,7 +471,15 @@ typedef enum
 {													\
 	mval			trig_val;								\
 													\
-	BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3);			 	\
+	BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3);				\
+	TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES);					\
+}
+
+#define	SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(SUB0, LEN0, SUB1, LEN1, SUB2, SUB3, VALUE, LEN, RES)	\
+{													\
+	mval			trig_val;								\
+													\
+	BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY_T(trig_val, SUB0, LEN0, SUB1, LEN1, SUB2, SUB3);		\
 	TRIGGER_GLOBAL_ASSIGNMENT_STR(trig_val, VALUE, LEN, RES);					\
 }
 
@@ -413,7 +488,7 @@ typedef enum
 	mval			trig_val;								\
 													\
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3);			\
-	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES);						\
+	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES);							\
 }
 
 #define	SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(SUB1, LEN1, SUB2, LEN2, SUB3, LEN3, VALUE, LEN, RES)		\
@@ -429,7 +504,7 @@ typedef enum
 	mval			trig_val;								\
 													\
 	BUILD_HASHT_SUB_SUB_SUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, LEN2, SUB3, LEN3);		\
-	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES);						\
+	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES);							\
 }
 
 #define	SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_MVAL(SUB1, LEN1, SUB2, SUB3, LEN3, SUB4, VALUE, RES)	\
@@ -437,7 +512,7 @@ typedef enum
 	mval			trig_val;								\
 													\
 	BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY_T(trig_val, SUB1, LEN1, SUB2, SUB3, LEN3, SUB4);		\
-	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(trig_val, VALUE, RES);						\
+	TRIGGER_GLOBAL_ASSIGNMENT_MVAL(VALUE, RES);							\
 }
 
 #define	SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_STR(SUB1, LEN1, SUB2, SUB3, LEN3, SUB4, VALUE, LEN, RES)	\
@@ -487,4 +562,40 @@ typedef enum
 	}									\
 }
 
+/* If this is the first call of this macro inside a function, then note down whatever is in the util_output buffer.
+ * This is the prefix that is already printed for the first "util_out_print_gtmio" call. For the second and future
+ * calls of the "util_out_print_gtmio" function inside the current function, print the noted down prefix first.
+ * This gives more user-friendly output (e.g. deleting wildcard triggers by name prints same Line # in each trigger
+ * that gets deleted).
+ */
+#define	UTIL_PRINT_PREFIX_IF_NEEDED(FIRST_GTMIO, UTILPREFIX, UTILPREFIXLEN)			\
+{												\
+	boolean_t	ret;									\
+												\
+	if (FIRST_GTMIO)									\
+	{											\
+		ret = util_out_save(UTILPREFIX, UTILPREFIXLEN);					\
+		assert(ret);	/* assert we have space to save prefix in UTILPREFIX */		\
+		/* If there was no space to save the prefix, print second and later calls of	\
+		 * "util_out_print_gtmio" without the prefix in pro.				\
+		 */										\
+		if (ret)									\
+			FIRST_GTMIO = FALSE;							\
+	} else											\
+		util_out_print_gtmio("!AD", NOFLUSH, *UTILPREFIXLEN, UTILPREFIX);		\
+}
+
+#define	SET_DISP_TRIGVN(REG, DISP_TRIGVN, DISP_TRIGVN_LEN, TRIGVN, TRIGVN_LEN)			\
+{												\
+	memcpy(DISP_TRIGVN, TRIGVN, TRIGVN_LEN);						\
+	DISP_TRIGVN_LEN = TRIGVN_LEN;								\
+	MEMCPY_LIT(&DISP_TRIGVN[DISP_TRIGVN_LEN], SPANREG_REGION_LIT);				\
+	DISP_TRIGVN_LEN += SPANREG_REGION_LITLEN;						\
+	memcpy(&DISP_TRIGVN[DISP_TRIGVN_LEN], REG->rname, REG->rname_len);			\
+	DISP_TRIGVN_LEN += REG->rname_len;							\
+	DISP_TRIGVN[DISP_TRIGVN_LEN++] = ')';							\
+	assert(DISP_TRIGVN_LEN < ARRAYSIZE(DISP_TRIGVN));					\
+	DISP_TRIGVN[DISP_TRIGVN_LEN] = '\0';	/* null terminate just in case */		\
+}
+
 #endif /* MUPIP_TRIGGER_INCLUDED */
diff --git a/sr_unix/trigger_compare.c b/sr_unix/trigger_compare.c
index cad5cc1..1d80891 100644
--- a/sr_unix/trigger_compare.c
+++ b/sr_unix/trigger_compare.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -26,7 +26,7 @@
 #include "trigger.h"
 #include "trigger_compare_protos.h"
 #include "trigger_gbl_fill_xecute_buffer.h"
-#include "mvalconv.h"			/* Needed for MV_FORCE_MVAL and MV_FORCE_UMVAL */
+#include "mvalconv.h"			/* Needed for MV_FORCE_UMVAL, MV_FORCE_* variants */
 #include "op.h"
 #include "nametabtyp.h"
 #include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
@@ -38,29 +38,36 @@
 #include "jnl.h"			/* needed for tp.h */
 #include "tp.h"
 #include "hashtab_mname.h"
+#include "t_retry.h"
 
 GBLREF	sgmnt_data_ptr_t	cs_data;
-GBLREF	gd_addr			*gd_header;
 GBLREF	gd_region		*gv_cur_region;
 GBLREF	gv_key			*gv_currkey;
 GBLREF	gv_namehead		*gv_target;
+GBLREF	unsigned int		t_tries;
 
-LITREF	mval			literal_hasht;
 LITREF	mval			literal_one;
 LITREF	mval			literal_ten;
 LITREF	char 			*trigger_subs[];
 
-#define NON_HASH	-1
-LITDEF int trig_subsc_xlate_tbl[11] =
+LITDEF int trig_subsc_partofhash[] =
 {
-	NON_HASH, 1, NON_HASH, NON_HASH, 4, 5, 6, 7, NON_HASH, NON_HASH, NON_HASH
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	PARTOFHASH,
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
 };
 
-#define COPY_VAL_TO_INDEX_STR(SUB, PTR)						\
-{										\
-	memcpy(PTR, values[SUB], value_len[SUB]);				\
-	PTR += value_len[SUB];							\
-	*PTR++ = '\0';								\
+#define COPY_VAL_TO_INDEX_STR(SUB, PTR)		\
+{						\
+	int	len;				\
+						\
+	len = value_len[SUB];			\
+	if (len)				\
+	{					\
+		memcpy(PTR, values[SUB], len);	\
+		PTR += len;			\
+		*PTR++ = '\0';			\
+	}					\
 }
 
 error_def(ERR_TRIGDEFBAD);
@@ -131,14 +138,15 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
 	int4			len;
 	mval			mv_hash;
 	boolean_t		match, multi_record;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	int			trig_index;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	collision_indx_ptr = &collision_indx;
 	MV_FORCE_UMVAL(&mv_hash, trigger_hash->hash_code);
-	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+	BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+		LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
 	while (TRUE)
 	{
 		op_gvorder(collision_indx_ptr);
@@ -148,30 +156,38 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
 			match = FALSE;
 			break;
 		}
-		BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+		BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
 		if (!gvcst_get(&key_val))
-		{	/* There has to be a #TRHASH entry */
-			assert(FALSE);
+		{	/* There has to be a #TRHASH entry or else it is a retry situation (due to concurrent updates) */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
 			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
 					LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
 		}
 		ptr = key_val.str.addr;
-		len = STRLEN(ptr);
-		if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
-		{
-			hash_index = 0;
-			match = FALSE;
-			break;
+		ptr2 = memchr(ptr, '\0', key_val.str.len);
+		if (NULL == ptr2)
+		{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+					LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
 		}
-		ptr += len;
-		assert(('\0' == *ptr) && (key_val.str.len > len));
-		ptr++;
-		A2I(ptr, key_val.str.addr + key_val.str.len, trig_index);
+		len = ptr2 - ptr;
+		if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
+			continue;
+		assert(0 != match_index);
+		assert(('\0' == *ptr2) && (key_val.str.len > len));
+		ptr2++;
+		A2I(ptr2, key_val.str.addr + key_val.str.len, trig_index);
 		assert(-1 != trig_index);
-		if ((0 == match_index) || (match_index == trig_index))
+		match = (match_index == trig_index);
+		if (match)
 		{
-			hash_index = MV_FORCE_INT(collision_indx_ptr);
-			match = TRUE;
+			hash_index = MV_FORCE_UINT(collision_indx_ptr);
 			break;
 		}
 	}
@@ -180,21 +196,20 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
 }
 
 boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *trigger_hash, int *hash_indx,
-			  int *trig_indx, int match_index, boolean_t doing_set)
+			  int *trig_indx, boolean_t doing_set)
 {
 	mval			collision_indx;
 	mval			*collision_indx_ptr;
 	mval			data_val;
-	mname_entry		gvname;
 	boolean_t		have_value;
 	mval			key_val;
 	int4			len;
-	boolean_t		multi_record;
+	boolean_t		multi_record, kill_cmp, first_match_kill_cmp;
 	mval			mv_hash;
 	mval			mv_trig_indx;
-	boolean_t		match;
+	boolean_t		match, first_match;
 	int4			num;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	int4			rec_len;
 	int			sub_indx;
 	mval			sub_val;
@@ -203,68 +218,93 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va
 	int			trig_index;
 	char			*xecute_buff;
 	int4			xecute_len;
-	gvnh_reg_t		*gvnh_reg;
+	unsigned char		util_buff[MAX_TRIG_UTIL_LEN];	/* needed for HASHT_GVN_DEFINITION_RETRY_OR_ERROR macro */
+	int4			util_len;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	collision_indx_ptr = &collision_indx;
 	MV_FORCE_UMVAL(&mv_hash, trigger_hash->hash_code);
-	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
-	xecute_buff = NULL;
+	BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+		LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+	DEBUG_ONLY(xecute_buff = NULL;)
+	first_match = TRUE;
 	while (TRUE)
 	{
 		match = TRUE;
 		op_gvorder(collision_indx_ptr);
 		if (0 == collision_indx_ptr->str.len)
 		{
-			trig_hash_index = trig_index = 0;
 			match = FALSE;
 			break;
 		}
-		BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+		BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
 		if (!gvcst_get(&key_val))
-		{	/* There has to be a #TRHASH entry */
-			assert(FALSE);
+		{	/* There has to be a #TRHASH entry or else it is a retry situation (due to concurrent updates) */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
 			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
 					LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
 		}
 		ptr = key_val.str.addr;
-		len = STRLEN(ptr);
+		ptr2 = memchr(ptr, '\0', key_val.str.len);
+		if (NULL == ptr2)
+		{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+					LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
+		}
+		len = ptr2 - ptr;
 		if ((len != trigvn_len) || (0 != memcmp(trigvn, ptr, len)))
-		{
-			trig_hash_index = trig_index = 0;
-			match = FALSE;
-			break;
+		{	/* We expect all hashes under ^#t(<gbl>,"#TRHASH",...) to correspond to <gbl> in their value.
+			 * If not this is a TRIGDEFBAD situation.
+			 */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+					LEN_AND_LIT("\"#TRHASH\""), mv_hash.str.len, mv_hash.str.addr);
 		}
 		ptr += len;
 		assert(('\0' == *ptr) && (key_val.str.len > len));
 		ptr++;
 		A2I(ptr, key_val.str.addr + key_val.str.len, trig_index);
 		assert(-1 != trig_index);
-		gvname.var_name.addr = trigvn;
-		gvname.var_name.len = trigvn_len;
-		COMPUTE_HASH_MNAME(&gvname);
-		GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
-		assert(cs_addrs == gv_target->gd_csa);
-		SET_GVTARGET_TO_HASHT_GBL(cs_addrs);
-		INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-		MV_FORCE_MVAL(&mv_trig_indx, trig_index);
+		MV_FORCE_UMVAL(&mv_trig_indx, trig_index);
 		for (sub_indx = 0; sub_indx < NUM_TOTAL_SUBS; sub_indx++)
 		{
-			if (NON_HASH == trig_subsc_xlate_tbl[sub_indx])
-				continue;
-			if (!doing_set && ((DELIM_SUB == sub_indx) || (ZDELIM_SUB == sub_indx) || (PIECES_SUB == sub_indx)))
+			if (((TRSBS_IN_NONE == trig_subsc_partofhash[sub_indx]) && (CMD_SUB != sub_indx))
+					|| (!doing_set && (TRSBS_IN_BHASH == trig_subsc_partofhash[sub_indx])))
 				continue;
+			assert((CMD_SUB == sub_indx) || ((TRSBS_IN_LHASH | TRSBS_IN_BHASH) == trig_subsc_partofhash[sub_indx])
+				|| (doing_set && (TRSBS_IN_BHASH == trig_subsc_partofhash[sub_indx])));
 			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, trigger_subs[sub_indx],
 							 STRLEN(trigger_subs[sub_indx]));
 			multi_record = FALSE;
 			have_value = gvcst_get(&key_val);
+			if (CMD_SUB == sub_indx)
+			{
+				if (!have_value || !key_val.str.len)
+				{	/* No CMD node. Retry situation (due to concurrent updates) */
+					HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trig_index, ",\"CMD\"", cs_addrs);
+				}
+				kill_cmp = ((NULL != memchr(key_val.str.addr, 'K', key_val.str.len))
+						|| (NULL != memchr(key_val.str.addr, 'R', key_val.str.len)));
+				continue;
+			}
 			if (!have_value && (XECUTE_SUB == sub_indx))
 			{
 				op_gvdata(&data_val);
 				multi_record = (literal_ten.m[0] == data_val.m[0]) && (literal_ten.m[1] == data_val.m[1]);
+				have_value = multi_record;
 			}
-			if ((0 == value_len[sub_indx]) && !have_value && !multi_record)
+			if ((0 == value_len[sub_indx]) && !have_value)
 				continue;
 			if (XECUTE_SUB == sub_indx)
 			{
@@ -272,45 +312,75 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va
 				xecute_buff = trigger_gbl_fill_xecute_buffer(trigvn, trigvn_len, &mv_trig_indx,
 									     multi_record ? NULL : &key_val, &xecute_len);
 				if ((value_len[sub_indx] == xecute_len)
-				    && (0 == memcmp(values[sub_indx], xecute_buff, value_len[sub_indx])))
+					&& (0 == memcmp(values[sub_indx], xecute_buff, value_len[sub_indx])))
 				{
 					free(xecute_buff);
-					xecute_buff = NULL;
+					DEBUG_ONLY(xecute_buff = NULL;)
 					continue;
 				} else
 				{
 					free(xecute_buff);
-					xecute_buff = NULL;
-					trig_hash_index = trig_index = 0;
+					DEBUG_ONLY(xecute_buff = NULL;)
 					match = FALSE;
 					break;
 				}
 			} else
 			{
 				if (have_value && (value_len[sub_indx] == key_val.str.len)
-				    && (0 == memcmp(values[sub_indx], key_val.str.addr, value_len[sub_indx])))
+						&& (0 == memcmp(values[sub_indx], key_val.str.addr, value_len[sub_indx])))
 					continue;
 				else
 				{
-					trig_hash_index = trig_index = 0;
 					match = FALSE;
 					break;
 				}
 			}
 		}
-		SWITCH_TO_DEFAULT_REGION;
-		if (!match || ((0 != match_index) && (match_index != trig_index)))
+		if (match)
 		{
-			BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash,
-							  collision_indx);
-			continue;
+			trig_hash_index = MV_FORCE_UINT(collision_indx_ptr);
+			assert(trig_index);
+			/* It is possible for 2 triggers to match (in case a KILL and SET trigger for same gvn/subs/xecute string
+			 * exists separately). In this case, based on "doing_set", we match the appropriate trigger. If 2 triggers
+			 * dont match, we use the only matching trigger even if the trigger type (set/kill) does not match.
+			 */
+			if (first_match)
+			{
+				*trig_indx = trig_index;
+				*hash_indx = trig_hash_index;
+				if (!doing_set && kill_cmp)
+					break;	/* KILL type trigger sought and found one. Stop at first. */
+				first_match = FALSE; /* search once more */
+				first_match_kill_cmp = kill_cmp;
+				/* Assume this is the only matching trigger for now. Later match if found will override */
+			} else
+			{
+				assert((first_match_kill_cmp != kill_cmp) || !kill_cmp);
+				/* We have TWO matches. Pick the more appropriate one. */
+				if (doing_set != kill_cmp)
+				{	/* Current trigger matches input trigger type. Overwrite first_match */
+					*trig_indx = trig_index;
+					*hash_indx = trig_hash_index;
+				}
+				/* else current trigger does not match input trigger type. Use first_match as is (already done) */
+				break;
+			}
 		}
-		trig_hash_index = MV_FORCE_INT(collision_indx_ptr);
-		match = TRUE;
-		break;
+		/* We did a BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY at the beginning of this for loop but gv_currkey would have been
+		 * overwritten in various places since then so reinitialize it before doing op_gvorder of next iteration.
+		 */
+		BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STR_LIT_LEN(LITERAL_HASHTRHASH), mv_hash, collision_indx);
+	}
+	if (!match)
+	{
+		if (first_match)
+		{
+			*trig_indx = 0;
+			*hash_indx = 0;
+		} else
+			match = TRUE;
 	}
-	*trig_indx = trig_index;
-	*hash_indx = trig_hash_index;
 	return match;
 }
 #endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_compare_protos.h b/sr_unix/trigger_compare_protos.h
index 3c2c092..7dbba8f 100644
--- a/sr_unix/trigger_compare_protos.h
+++ b/sr_unix/trigger_compare_protos.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -19,5 +19,5 @@ void build_set_cmp_str(char *trigvn, int trigvn_len, char **values, uint4 *value
 
 boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_hash, int trig_indx, int *hash_indx);
 boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *trigger_hash, int *hash_indx,
-	int *trig_indx, int match_index, boolean_t doing_set);
+	int *trig_indx, boolean_t doing_set);
 #endif
diff --git a/sr_unix/trigger_delete.c b/sr_unix/trigger_delete.c
index 5ce31ba..f03c832 100644
--- a/sr_unix/trigger_delete.c
+++ b/sr_unix/trigger_delete.c
@@ -30,7 +30,7 @@
 #include "mv_stent.h"			/* for COPY_SUBS_TO_GVCURRKEY macro */
 #include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
 #include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL */
 #include "hashtab_str.h"
 #include "wbox_test_init.h"
 #include "trigger_delete_protos.h"
@@ -55,19 +55,15 @@ GBLREF	gd_addr			*gd_header;
 GBLREF	gd_region		*gv_cur_region;
 GBLREF	gv_key			*gv_currkey;
 GBLREF	gv_namehead		*gv_target;
-GBLREF	gv_namehead		*gv_target_list;
 GBLREF	sgm_info		*sgm_info_ptr;
 GBLREF	sgmnt_data_ptr_t	cs_data;
-GBLREF	trans_num		local_tn;
 GBLREF	uint4			dollar_tlevel;
 
-LITREF	mval			literal_hasht;
 LITREF	char 			*trigger_subs[];
 
 error_def(ERR_TEXT);
 error_def(ERR_TRIGDEFBAD);
 error_def(ERR_TRIGLOADFAIL);
-error_def(ERR_TRIGMODINTP);
 error_def(ERR_TRIGMODREGNOTRW);
 error_def(ERR_TRIGNAMBAD);
 
@@ -78,71 +74,52 @@ error_def(ERR_TRIGNAMBAD);
 {											\
 	if (CDB_STAGNATE > t_tries)							\
 		t_retry(cdb_sc_triggermod);						\
-	else										\
-	{										\
-		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);	\
-		rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len,	\
-				trigvn, LEN_AND_LIT("\"#TRHASH\""),HASH->str.len,	\
-				HASH->str.addr);					\
-	}										\
+	assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);		\
+	rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len,		\
+			trigvn, LEN_AND_LIT("\"#TRHASH\""),HASH->str.len,		\
+			HASH->str.addr);						\
 }
 
-#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA)							\
-{																\
-	mval			mv_hash_indx;											\
-	mval			mv_hash_val;											\
-	int			hash_index;											\
-																\
-	if (search_trigger_hash(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, &hash_index)) 						\
-	{															\
-		MV_FORCE_UMVAL(&mv_hash_val, HASH->hash_code);									\
-		MV_FORCE_MVAL(&mv_hash_indx, hash_index);									\
-		BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash_val, mv_hash_indx);	\
-		gvcst_kill(FALSE);												\
-	} else															\
-	{	/* There has to be a #TRHASH entry */										\
-		TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA);									\
-	}															\
+#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA)				\
+{													\
+	mval			mv_hash_indx;								\
+	mval			mv_hash_val;								\
+	int			hash_index;								\
+													\
+	if (search_trigger_hash(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, &hash_index)) 			\
+	{												\
+		MV_FORCE_UMVAL(&mv_hash_val, HASH->hash_code);						\
+		MV_FORCE_UMVAL(&mv_hash_indx, hash_index);						\
+		BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(TRIGVN, TRIGVN_LEN,				\
+			LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash_val, mv_hash_indx);	\
+		gvcst_kill(FALSE);									\
+	} else												\
+	{	/* There has to be a #TRHASH entry */							\
+		TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA);						\
+	}												\
 }
 
-STATICFNDEF void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
+void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
 		stringkey *kill_hash, boolean_t del_kill_hash, int match_index)
 {
 	sgmnt_addrs		*csa;
 	uint4			len;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
-	mstr			trigger_key;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
 	csa = cs_addrs;
-	assert(0 != gv_target->root);
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	if (NULL != strchr(values[CMD_SUB], 'S'))
-	{
+	assert(!gv_cur_region->read_only);	/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
+	if ((NULL != strchr(values[CMD_SUB], 'S')) && (set_hash->hash_code != kill_hash->hash_code))
 		SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, set_hash, match_index, csa)
-	}
 	if (del_kill_hash)
-	{
 		SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, kill_hash, match_index, csa);
-	}
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
 }
 
-STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len)
+void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len)
 {
 	int4			result;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	gv_namehead		*save_gvtarget;
-	sgm_info		*save_sgm_info_ptr;
 	char			trunc_name[MAX_TRIGNAME_LEN + 1];
 	uint4			used_trigvn_len;
 	mval			val;
@@ -153,29 +130,24 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	assert(!gv_cur_region->read_only);	/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	/* assume user defined name or auto gen name whose GVN < 21 chars */
-	is_auto_name = FALSE;
 	if (!trigger_user_name(trigger_name, trigger_name_len))
 	{	/* auto gen name uses #TNCOUNT and #SEQNO under #TNAME */
 		is_auto_name = TRUE;
 		used_trigvn_len = MIN(trigvn_len, MAX_AUTO_TRIGNAME_LEN);
 		memcpy(trunc_name, trigvn, used_trigvn_len);
-	}
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	if (0 != gv_target->root)
-	{
-		if (gv_cur_region->read_only)
-			rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
 		if (is_auto_name)
 		{
 			/* $get(^#t("#TNAME",<trunc_name>,"#TNCOUNT")) */
 			BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trunc_name,
 							used_trigvn_len, LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT));
 			if (gvcst_get(&val))
-			{	 /* only long autogenerated names have a #TNCOUNT entry */
+			{	 /* each autogenerated name has a #TNCOUNT entry */
 				val_ptr = &val;
-				var_count = MV_FORCE_INT(val_ptr);
+				var_count = MV_FORCE_UINT(val_ptr);
 				if (1 == var_count)
 				{
 					/* kill ^#t("#TNAME",<trunc_name>) to kill #TNCOUNT and #SEQNO */
@@ -185,7 +157,7 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
 				} else
 				{
 					var_count--;
-					MV_FORCE_MVAL(&val, var_count);
+					MV_FORCE_UMVAL(&val, var_count);
 					/* set ^#t("#TNAME",GVN,"#TNCOUNT")=var_count */
 					SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME),
 									trunc_name, used_trigvn_len, LITERAL_HASHTNCOUNT,
@@ -194,61 +166,59 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
 				}
 			}
 		}
-		/* kill ^#t("#TNAME",<trigger_name>,:) or zkill ^#t("#TNAME",<trigger_name>) if is_auto_name==FALSE */
-		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name,
-					    trigger_name_len - 1);
-		gvcst_kill(is_auto_name);
-	}
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
+	} else
+		is_auto_name = FALSE;
+	/* kill ^#t("#TNAME",<trigger_name>,:) or zkill ^#t("#TNAME",<trigger_name>) if is_auto_name==FALSE */
+	BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name,
+				    trigger_name_len - 1);
+	gvcst_kill(is_auto_name);
 }
 
-STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int trig_name_len, int new_trig_index)
+STATICFNDEF int4 update_trigger_name_value(char *trig_name, int trig_name_len, int new_trig_index)
 {
 	int			len;
 	char			name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
 	char			new_trig_name[MAX_TRIGNAME_LEN + 1];
 	int			num_len;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	int4			result;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
 	mval			trig_gbl;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	if (MAX_AUTO_TRIGNAME_LEN < trigvn_len)
-		return PUT_SUCCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	assert(0 != gv_target->root);
+	assert(!gv_cur_region->read_only);		/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	/* $get(^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) */
 	BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1);
 	if (!gvcst_get(&trig_gbl))
 	{	/* There has to be a #TNAME entry */
 		if (CDB_STAGNATE > t_tries)
 			t_retry(cdb_sc_triggermod);
-		else
-		{
-			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1,
-					trig_name);
-		}
+		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
+			trig_name_len - 1, trig_name);
 	}
-	len = STRLEN(trig_gbl.str.addr) + 1;
+	ptr = trig_gbl.str.addr;
+	ptr2 = memchr(ptr, '\0', trig_gbl.str.len);
+	if (NULL == ptr2)
+	{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+		if (CDB_STAGNATE > t_tries)
+			t_retry(cdb_sc_triggermod);
+		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
+			trig_name_len - 1, trig_name);
+	}
+	len = (ptr2 - ptr) + 1;
 	assert(MAX_MIDENT_LEN >= len);
 	memcpy(name_and_index, trig_gbl.str.addr, len);
 	ptr = name_and_index + len;
 	num_len = 0;
 	I2A(ptr, num_len, new_trig_index);
 	len += num_len;
-	/* set ^#t(GVN,index,"#TRIGNAME")=trig_name $C(0) new_trig_index */
+	/* set ^#t("#TNAME",<trigname>)=gblname_$C(0)_new_trig_index */
 	SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1,
 		name_and_index, len, result);
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
 	return result;
 }
 
@@ -262,79 +232,86 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **
 	mval			mv_hash;
 	mval			mv_hash_indx;
 	int			num_len;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	int4			result;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
 	char			tmp_str[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
+	assert(!gv_cur_region->read_only);		/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	csa = cs_addrs;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	assert(0 != gv_target->root);
-	if (NULL != strchr(values[CMD_SUB], 'S'))
+	if ((NULL != strchr(values[CMD_SUB], 'S')) && (set_hash->hash_code != kill_hash->hash_code))
 	{
 		if (!search_trigger_hash(trigvn, trigvn_len, set_hash, old_trig_index, &hash_index))
 		{	/* There has to be an entry with the old hash value, we just looked it up */
 			TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash, csa);
 		}
 		MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
-		MV_FORCE_MVAL(&mv_hash_indx, hash_index);
-		BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
+		MV_FORCE_UMVAL(&mv_hash_indx, hash_index);
+		BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
 		if (!gvcst_get(&key_val))
 		{	/* There has to be a #TRHASH entry */
 			TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash, csa);
 		}
 		assert((MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT) >= key_val.str.len);
-		len = STRLEN(key_val.str.addr);
+		ptr = key_val.str.addr;
+		ptr2 = memchr(ptr, '\0', key_val.str.len);
+		if (NULL == ptr2)
+		{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+					LEN_AND_LIT("\"#BHASH\""), mv_hash.str.len, mv_hash.str.addr);
+		}
+		len = ptr2 - ptr;
 		memcpy(tmp_str, key_val.str.addr, len);
 		ptr = tmp_str + len;
 		*ptr++ = '\0';
 		num_len = 0;
 		I2A(ptr, num_len, new_trig_index);
 		len += num_len + 1;
-		SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx,
-			tmp_str, len, result);
+		SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx, tmp_str, len, result);
 		if (PUT_SUCCESS != result)
-		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 			return result;
-		}
 	}
 	if (!search_trigger_hash(trigvn, trigvn_len, kill_hash, old_trig_index, &hash_index))
 	{	/* There has to be an entry with the old hash value, we just looked it up */
 		TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash, csa);
 	}
 	MV_FORCE_UMVAL(&mv_hash, kill_hash->hash_code);
-	MV_FORCE_MVAL(&mv_hash_indx, hash_index);
-	BUILD_HASHT_SUB_MSUB_MSUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
+	MV_FORCE_UMVAL(&mv_hash_indx, hash_index);
+	BUILD_HASHT_SUB_SUB_MSUB_MSUB_CURRKEY(trigvn, trigvn_len,
+		LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx);
 	if (!gvcst_get(&key_val))
 	{	/* There has to be a #TRHASH entry */
 		TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash, csa);
 	}
 	assert((MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT) >= key_val.str.len);
-	len = STRLEN(key_val.str.addr);
+	ptr = key_val.str.addr;
+	ptr2 = memchr(ptr, '\0', key_val.str.len);
+	if (NULL == ptr2)
+	{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+		if (CDB_STAGNATE > t_tries)
+			t_retry(cdb_sc_triggermod);
+		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+		rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+				LEN_AND_LIT("\"#LHASH\""), mv_hash.str.len, mv_hash.str.addr);
+	}
+	len = ptr2 - ptr;
 	memcpy(tmp_str, key_val.str.addr, len);
 	ptr = tmp_str + len;
 	*ptr++ = '\0';
 	num_len = 0;
 	I2A(ptr, num_len, new_trig_index);
 	len += num_len + 1;
-	SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx,
-		tmp_str, len, result);
-	if (PUT_SUCCESS != result)
-	{
-		RESTORE_TRIGGER_REGION_INFO(save_currkey);
-		return result;
-	}
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
-	return PUT_SUCCESS;
+	SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+		LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_hash_indx, tmp_str, len, result);
+	return result;
 }
 
 boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats)
@@ -342,15 +319,13 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
 	sgmnt_addrs		*csa;
 	char			curr_name[MAX_MIDENT_LEN + 1];
 	uint4			curr_name_len, orig_name_len;
-	mname_entry		gvname;
 	mval			mv_curr_nam;
-	boolean_t		name_found;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	char			*name_tail_ptr;
+	char			save_name[MAX_MIDENT_LEN + 1];
 	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
+	gd_region		*save_gv_cur_region, *lgtrig_reg;
 	gv_namehead		*save_gv_target;
-	char			save_name[MAX_MIDENT_LEN + 1];
 	sgm_info		*save_sgm_info_ptr;
 	mval			trig_gbl;
 	mval			trig_value;
@@ -360,9 +335,18 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
 	int			trig_indx;
 	int			badpos;
 	boolean_t		wildcard;
-	gvnh_reg_t		*gvnh_reg;
+	char			utilprefix[1024];
+	int			utilprefixlen;
+	boolean_t		first_gtmio;
+	uint4			triggers_deleted;
 	mval			trigjrec;
 	boolean_t		jnl_format_done;
+	gd_region		*reg, *reg_top;
+	char			disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1];
+					/* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name,
+					 * 1 for ")" and 1 for trailing '\0'.
+					 */
+	int			disp_trigvn_len;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
@@ -371,144 +355,168 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
 	trigjrec.str.len = trigger_name_len--;
 	trigjrec.str.addr = trigger_name++;
 	orig_name_len = trigger_name_len;
-	if ((0 == trigger_name_len) || (trigger_name_len !=
-			(badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
+	if ((0 == trigger_name_len)
+		|| (trigger_name_len != (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
 	{	/* is the input name valid */
 		CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name);
 		/* badpos is the string position where the bad character was found, pretty print it */
+		trig_stats[STATS_ERROR_TRIGFILE]++;
 		return TRIG_FAILURE;
 	}
 	name_tail_ptr = trigger_name + trigger_name_len - 1;
-	if (TRIGNAME_SEQ_DELIM == *name_tail_ptr || wildcard )
-		/* drop the trailing # sign or wildcard */
-		trigger_name_len--;
-	/* $data(^#t) */
-	SWITCH_TO_DEFAULT_REGION;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	if (0 == gv_target->root)
-	{
-		util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
-		trig_stats[STATS_UNCHANGED]++;
-		return TRIG_SUCCESS;
-	}
-	/* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
+	if ((TRIGNAME_SEQ_DELIM == *name_tail_ptr) || wildcard)
+		trigger_name_len--; /* drop the trailing # sign for wildcard */
 	jnl_format_done = FALSE;
-	csa = cs_addrs;
-	if (JNL_WRITE_LOGICAL_RECS(csa))
+	lgtrig_reg = NULL;
+	first_gtmio = TRUE;
+	triggers_deleted = 0;
+	assert(trigger_name_len < MAX_MIDENT_LEN);
+	memcpy(save_name, trigger_name, trigger_name_len);
+	save_name[trigger_name_len] = '\0';
+	utilprefixlen = ARRAYSIZE(utilprefix);
+	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
 	{
-		assert(!gv_cur_region->read_only);
-		/* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in case this is a NO-OP
-		 * trigger operation that wont happen and we still want to write a TLGTRIG/ULGTRIG journal record. Hence
-		 * the need to do this.
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+		csa = cs_addrs;
+		if (NULL == csa)	/* not BG or MM access method */
+			continue;
+		/* gv_target now points to ^#t in region "reg" */
+		/* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
+		if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+			lgtrig_reg = reg;
+		if (!gv_target->root)
+			continue;
+		memcpy(curr_name, save_name, trigger_name_len);
+		curr_name_len = trigger_name_len;
+		do {
+			/* GVN = $get(^#t("#TNAME",curr_name) */
+			BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
+			if (gvcst_get(&trig_gbl))
+			{
+				if (reg->read_only)
+					rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+				SAVE_TRIGGER_REGION_INFO(save_currkey);
+				ptr = trig_gbl.str.addr;
+				ptr2 = memchr(ptr, '\0', trig_gbl.str.len);
+				if (NULL == ptr2)
+				{	/* We expect $c(0) in the middle of ptr. If not found, this is a restartable situation */
+					if (CDB_STAGNATE > t_tries)
+						t_retry(cdb_sc_triggermod);
+					assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
+							curr_name_len, curr_name);
+				}
+				trigvn_len = ptr2 - ptr;
+				assert(MAX_MIDENT_LEN >= trigvn_len);
+				memcpy(trigvn, ptr, trigvn_len);
+				ptr += trigvn_len + 1;
+				/* the index is just beyond the length of the GVN string */
+				A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
+				SET_DISP_TRIGVN(reg, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+				/* $get(^#t(GVN,"COUNT") */
+				BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
+				if (!gvcst_get(&trigger_count))
+				{
+					UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+					util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
+							"but global ^!AD has no triggers",
+							FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
+					trig_stats[STATS_ERROR_TRIGFILE]++;
+					return TRIG_FAILURE;
+				}
+				if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+				{
+					jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+					jnl_format_done = TRUE;
+				}
+				/* kill the target trigger for GVN at index trig_indx */
+				if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx)))
+				{
+					UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+					util_out_print_gtmio("Trigger named !AD exists in the lookup table for global ^!AD,"	\
+								" but was not deleted!", FLUSH, orig_name_len, trigger_name,
+								disp_trigvn_len, disp_trigvn);
+					trig_stats[STATS_ERROR_TRIGFILE]++;
+					return TRIG_FAILURE;
+				} else
+				{
+					csa->incr_db_trigger_cycle = TRUE;
+					trigger_incr_cycle(trigvn, trigvn_len);	/* ^#t records changed, increment cycle */
+					if (dollar_ztrigger_invoked)
+					{	/* Increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this
+						 * transaction, on this region, will re-read triggers. See trigger_update.c
+						 * for a comment on why it is okay for db_dztrigger_cycle to be incremented
+						 * more than once in the same transaction.
+						 */
+						csa->db_dztrigger_cycle++;
+					}
+					trig_stats[STATS_DELETED]++;
+					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+					{
+						UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+						util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
+								FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
+					}
+				}
+				RESTORE_TRIGGER_REGION_INFO(save_currkey);
+				triggers_deleted++;
+			}
+			if (!wildcard)
+				/* not a wild card, don't $order for the next match */
+				break;
+			op_gvorder(&mv_curr_nam);
+			if (0 == mv_curr_nam.str.len)
+				break;
+			assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
+			memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
+			curr_name_len = mv_curr_nam.str.len;
+			if (0 != memcmp(curr_name, save_name, trigger_name_len))
+				/* stop when gv_order returns a string that no longer starts save_name */
+				break;
+		} while (TRUE);
+	}
+	if (!jnl_format_done && (NULL != lgtrig_reg))
+	{	/* There was no journaled region that had a ^#t update, but found at least one journaled region
+		 * so write a LGTRIG logical jnl record there.
+		 */
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
+		csa = cs_addrs;
+		/* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in
+		 * case this is a NO-OP trigger operation that wont update any ^#t records and we still
+		 * want to write a TLGTRIG/ULGTRIG journal record. Hence the need to do this.
 		 */
 		JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);
 		assert(dollar_tlevel);
-		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
-									 * even if NO db updates happen to ^#t nodes. */
+		/* below is needed to set update_trans TRUE on this region even if NO db updates happen to ^#t nodes */
+		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);
 		jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
 		jnl_format_done = TRUE;
 	}
-	name_found = FALSE;
-	assert(trigger_name_len < MAX_MIDENT_LEN);
-	memcpy(save_name, trigger_name, trigger_name_len);
-	save_name[trigger_name_len] = '\0';
-	memcpy(curr_name, save_name, trigger_name_len);
-	curr_name_len = trigger_name_len;
-	STR2MVAL(mv_curr_nam, trigger_name, trigger_name_len);
-	do {
-		/* GVN = $get(^#t("#TNAME",curr_name) */
-		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
-		if (gvcst_get(&trig_gbl))
-		{
-			SAVE_TRIGGER_REGION_INFO(save_currkey);
-			ptr = trig_gbl.str.addr;
-			trigvn_len = STRLEN(trig_gbl.str.addr);
-			assert(MAX_MIDENT_LEN >= trigvn_len);
-			memcpy(trigvn, ptr, trigvn_len);
-			ptr += trigvn_len + 1;
-			/* the index is just beyon the length of the GVN string */
-			A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
-			gvname.var_name.addr = trigvn;
-			gvname.var_name.len = trigvn_len;
-			COMPUTE_HASH_MNAME(&gvname);
-			GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
-			assert(cs_addrs == gv_target->gd_csa);
-			csa = cs_addrs;
-			if (gv_cur_region->read_only)
-				rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-			/* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
-			if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
-			{
-				assert(!gv_cur_region->read_only);
-				JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl); /* see previous usage for why it is needed */
-				assert(dollar_tlevel);
-				T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL); /* needed to set update_trans TRUE on this region
-										  * even if NO db updates happen to ^#t nodes. */
-				jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
-				jnl_format_done = TRUE;
-			}
-			SET_GVTARGET_TO_HASHT_GBL(csa);
-			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-			/* $get(^#t(GVN,"COUNT") */
-			BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
-			if (!gvcst_get(&trigger_count))
-			{
-				util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
-						"but global ^!AD has no triggers",
-						FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
-				return TRIG_FAILURE;
-			}
-			/* kill the target trigger for GVN at index trig_indx */
-			if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx)))
-			{
-				util_out_print_gtmio("Trigger named !AD exists in the lookup table, but was not deleted!",
-						FLUSH, orig_name_len, trigger_name);
-			} else
-			{
-				csa->incr_db_trigger_cycle = TRUE;
-				if (dollar_ztrigger_invoked)
-				{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
-					 * on this region, will re-read triggers. See trigger_update.c for a comment on why
-					 * it is okay for db_dztrigger_cycle to be incremented more than once in the same
-					 * transaction
-					 */
-					csa->db_dztrigger_cycle++;
-				}
-				trig_stats[STATS_DELETED]++;
-				if (0 == trig_stats[STATS_ERROR])
-					util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
-							FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
-			}
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
-			name_found = TRUE;
-		}
-		if (!wildcard)
-			/* not a wild card, don't $order for the next match */
-			break;
-		op_gvorder(&mv_curr_nam);
-		if (0 == mv_curr_nam.str.len)
-			break;
-		assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
-		memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
-		curr_name_len = mv_curr_nam.str.len;
-		if (0 != memcmp(curr_name, save_name, trigger_name_len))
-			/* stop when gv_order returns a string that no longer starts save_name */
-			break;
-	} while (wildcard);
-	if (!name_found)
+	if (wildcard)
 	{
-		util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
-		if (wildcard)
-			return TRIG_FAILURE;
-		else
+		UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+		if (triggers_deleted)
 		{
-			trig_stats[STATS_UNCHANGED]++;
-			return TRIG_SUCCESS;
+			trig_stats[STATS_NOERROR_TRIGFILE]++;
+			util_out_print_gtmio("All existing triggers named !AD (count = !UL) now deleted",
+				FLUSH, orig_name_len, trigger_name, triggers_deleted);
+		} else
+		{
+			trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+			util_out_print_gtmio("No matching triggers of the form !AD found for deletion",
+				FLUSH, orig_name_len, trigger_name);
 		}
+	} else if (triggers_deleted)
+	{
+		/* util_out_print_gtmio of "Deleted trigger named ..." already done so no need to do it again */
+		trig_stats[STATS_NOERROR_TRIGFILE]++;
 	} else
-		return TRIG_SUCCESS;
+	{	/* No names match. But treat it as a no-op (i.e. success). */
+		UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+		util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
+		trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+	}
+	return TRIG_SUCCESS;
 }
 
 int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index)
@@ -540,15 +548,21 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	assert(!gv_cur_region->read_only);		/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	mv_val_ptr = &mv_val;
-	MV_FORCE_MVAL(&trigger_index, index);
-	count = MV_FORCE_INT(trigger_count);
+	MV_FORCE_UMVAL(&trigger_index, index);
+	count = MV_FORCE_UINT(trigger_count);
 	/* build up array of values - needed for comparison in hash stuff */
 	ptr1 = tmp_trig_str;
 	memcpy(ptr1, trigvn, trigvn_len);
 	ptr1 += trigvn_len;
 	*ptr1++ = '\0';
 	tmp_len = trigvn_len + 1;
+	/* Assert that BHASH and LHASH are not part of NUM_SUBS calculation (confirms the -2 done in the #define of NUM_SUBS) */
+	assert(BHASH_SUB == NUM_SUBS);
+	assert(LHASH_SUB == (NUM_SUBS + 1));
 	for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
 	{
 		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[sub_indx],
@@ -556,6 +570,14 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 		trig_len = gvcst_get(&trigger_value) ? trigger_value.str.len : 0;
 		if (0 == trig_len)
 		{
+			if (((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) || (CHSET_SUB == sub_indx)))
+			{ /* CMD, NAME and CHSET cannot be zero length */
+				if (CDB_STAGNATE > t_tries)
+					t_retry(cdb_sc_triggermod);
+				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+						trigvn_len, trigvn, STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
+			}
 			tt_val[sub_indx] = NULL;
 			tt_val_len[sub_indx] = 0;
 			continue;
@@ -585,21 +607,23 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 	/* Get trigger name, set hash value, and kill hash values from trigger before we delete it.
 	 * The values will be used in clean ups associated with the deletion
 	 */
-	/* $get(^#t(GVN,trigger_index,"LHASH") for deletion in  cleanup_trigger_hash */
+	/* $get(^#t(GVN,trigger_index,"LHASH") for deletion in cleanup_trigger_hash */
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[LHASH_SUB],
 		STRLEN(trigger_subs[LHASH_SUB]));
 	if (gvcst_get(mv_val_ptr))
-		kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
-	else {
+		kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
+	else
+	{
 		util_out_print_gtmio("The LHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
 		kill_hash.hash_code = 0;
 	}
-	/* $get(^#t(GVN,trigger_index,"BHASH") for deletion in  cleanup_trigger_hash */
+	/* $get(^#t(GVN,trigger_index,"BHASH") for deletion in cleanup_trigger_hash */
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[BHASH_SUB],
 		STRLEN(trigger_subs[BHASH_SUB]));
 	if (gvcst_get(mv_val_ptr))
-		set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
-	else {
+		set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
+	else
+	{
 		util_out_print_gtmio("The BHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
 		set_hash.hash_code = 0;
 	}
@@ -615,7 +639,7 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
 		gvcst_kill(TRUE);
 		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
-		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, 0);
+		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
 	} else
 	{
 		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
@@ -642,7 +666,7 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 						trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), trigger_value, result);
 					assert(PUT_SUCCESS == result);
 				} else if (XECUTE_SUB == sub_indx)
-				{ /* multi line trigger broken up because it exceeds record size */
+				{	/* multi line trigger broken up because it exceeds record size */
 					for (xecute_idx = 0; ; xecute_idx++)
 					{
 						i2mval(&xecute_index, xecute_idx);
@@ -663,13 +687,10 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 					{ /* CMD, NAME and CHSET cannot be zero length */
 						if (CDB_STAGNATE > t_tries)
 							t_retry(cdb_sc_triggermod);
-						else
-						{
-							assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
-							rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
-									6, trigvn_len, trigvn, trigvn_len, trigvn,
-									STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
-						}
+						assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+						rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
+								6, trigvn_len, trigvn, trigvn_len, trigvn,
+								STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
 					}
 					/* OPTIONS, PIECES and DELIM can be zero */
 					trig_len = 0;
@@ -691,19 +712,19 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 							 STRLEN(trigger_subs[LHASH_SUB]));
 			if (!gvcst_get(mv_val_ptr))
 				return PUT_SUCCESS;
-			kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
+			kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
 			/* $get(^#t(GVN,trigger_count,"BHASH") for update_trigger_hash_value */
 			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[BHASH_SUB],
 							 STRLEN(trigger_subs[BHASH_SUB]));
 			if (!gvcst_get(mv_val_ptr))
 				return PUT_SUCCESS;
-			set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
+			set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
 			/* update hash values from above */
 			if (VAL_TOO_LONG == (retval = update_trigger_hash_value(trigvn, trigvn_len, tt_val, tt_val_len,
 					&set_hash, &kill_hash, count, index)))
 				return VAL_TOO_LONG;
 			/* fix the value ^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) to point to the correct "index" */
-			if (VAL_TOO_LONG == (retval = update_trigger_name_value(trigvn_len, tt_val[TRIGNAME_SUB],
+			if (VAL_TOO_LONG == (retval = update_trigger_name_value(tt_val[TRIGNAME_SUB],
 					tt_val_len[TRIGNAME_SUB], index)))
 				return VAL_TOO_LONG;
 			/* kill ^#t(GVN,COUNT) which was just shifted to trigger_index */
@@ -712,158 +733,125 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
 		}
 		/* Update #COUNT */
 		count--;
-		MV_FORCE_MVAL(trigger_count, count);
+		MV_FORCE_UMVAL(trigger_count, count);
 		SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT), *trigger_count,
 			result);
 		assert(PUT_SUCCESS == result);		/* Size of count can only get shorter or stay the same */
 	}
-	trigger_incr_cycle(trigvn, trigvn_len);
 	return PUT_SUCCESS;
 }
 
-void trigger_delete_all(char *trigger_rec, uint4 len)
+void trigger_delete_all(char *trigger_rec, uint4 len, uint4 *trig_stats)
 {
 	int			count;
 	char			count_str[MAX_DIGITS_IN_INT + 1];
 	sgmnt_addrs		*csa;
 	mval			curr_gbl_name;
 	int			cycle;
-	gv_namehead		*gvt;
 	mval			*mv_count_ptr;
 	mval			*mv_cycle_ptr;
 	mval			mv_indx;
-	gd_region		*reg;
-	int			reg_indx;
+	gd_region		*reg, *reg_top;
 	int4			result;
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
+	gd_region		*lgtrig_reg;
 	int			trig_indx;
 	mval			trigger_cycle;
 	mval			trigger_count;
 	mval			val;
+	boolean_t		this_db_updated;
+	uint4			triggers_deleted;
 	mval			trigjrec;
 	boolean_t		jnl_format_done;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	assert(0 < dollar_tlevel);
-	/* Before we delete any triggers, verify that none of the triggers have been fired in this transaction. If they have,
-	 * this creates an un-commitable transaction that will end in a TPFAIL error. Since that error indicates database
-	 * damage, we'd rather detect this avoidable condition and give a descriptive error instead (TRIGMODINTP).
-	 */
-	for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh)
-	{
-		if (gvt->trig_local_tn == local_tn)
-			rts_error_csa(CSA_ARG(gvt->gd_csa) VARLSTCNT(1) ERR_TRIGMODINTP);
-	}
-	SWITCH_TO_DEFAULT_REGION;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
 	jnl_format_done = FALSE;
+	lgtrig_reg = NULL;
 	trigjrec.mvtype = MV_STR;
 	trigjrec.str.len = len;
 	trigjrec.str.addr = trigger_rec;
-	if (0 != gv_target->root)
+	triggers_deleted = 0;
+	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
 	{
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
 		csa = cs_addrs;
-		/* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
-		if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
-		{
-			JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);	/* see previous usage for comment on why it is needed */
-			assert(dollar_tlevel);
-			T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
-										 * even if NO db updates happen to ^#t nodes. */
-			jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
-			jnl_format_done = TRUE;
-		}
-		/* kill ^#t("#TRHASH") */
-		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
-		if (0 != gvcst_data())
-			gvcst_kill(TRUE);
+		if (NULL == csa)	/* not BG or MM access method */
+			continue;
+		/* gv_target now points to ^#t in region "reg" */
+		/* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
+		if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+			lgtrig_reg = reg;
+		if (!gv_target->root)
+			continue;
 		/* kill ^#t("#TNAME") */
 		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
 		if (0 != gvcst_data())
+		{	/* Issue error if we dont have permissions to touch ^#t global */
+			if (reg->read_only)
+				rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
 			gvcst_kill(TRUE);
-	}
-	for (reg_indx = 0, reg = gd_header->regions; reg_indx < gd_header->n_regions; reg_indx++, reg++)
-	{
-		if (!reg->open)
-			gv_init_reg(reg);
-		gv_cur_region = reg;
-		change_reg();
-		csa = cs_addrs;
-		/* To write the LGTRIG logical jnl record, choose the first region that has journaling enabled */
-		if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
-		{
-			JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);	/* see previous usage for comment on why it is needed */
-			assert(dollar_tlevel);
-			T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
-										 * even if NO db updates happen to ^#t nodes. */
-			jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
-			jnl_format_done = TRUE;
 		}
-		SET_GVTARGET_TO_HASHT_GBL(csa);
-		INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-		/* There might not be any ^#t in this region, so check */
-		if (0 != gv_target->root)
-		{	/* Give error on region only if it has #t global indicating the presence
-			 * of triggers.
-			 */
-			if (reg->read_only)
-				rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, REG_LEN_STR(reg));
-			/* Kill all descendents of ^#t(trigvn, indx) where trigvn is any global with a trigger,
-			 * but skip the "#XYZ" entries. setup ^#t(trigvn,"$") as the PREV key for op_gvorder
-			 */
-			BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
-			TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
-			while (TRUE)
+		/* Kill all descendents of ^#t(trigvn, ...) where trigvn is any global with a trigger,
+		 * but skip the ^#t("#...",...) entries. Setup ^#t("$") as the key for op_gvorder
+		 */
+		BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
+		TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
+		this_db_updated = FALSE;
+		while (TRUE)
+		{
+			op_gvorder(&curr_gbl_name);
+			/* quit:$length(curr_gbl_name)=0 */
+			if (0 == curr_gbl_name.str.len)
+				break;
+			/* $get(^#t(curr_gbl_name,#COUNT)) */
+			BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+							LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
+			if (gvcst_get(&trigger_count))
 			{
-				op_gvorder(&curr_gbl_name);
-				/* quit:$length(curr_gbl_name)=0 */
-				if (0 == curr_gbl_name.str.len)
-					break;
-				/* $get(^#t(curr_gbl_name,#COUNT)) */
-					BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
-						LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
-					if (gvcst_get(&trigger_count))
-					{
-						mv_count_ptr = &trigger_count;
-						count = MV_FORCE_INT(mv_count_ptr);
-						/* $get(^#t(curr_gbl_name,#CYCLE)) */
-						BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
-							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
-						if (!gvcst_get(&trigger_cycle))
-						{	/* Found #COUNT, there must be #CYCLE */
-							if (CDB_STAGNATE > t_tries)
-								t_retry(cdb_sc_triggermod);
-							else
-							{
-								assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
-								rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
-										curr_gbl_name.str.len, curr_gbl_name.str.addr,
-										curr_gbl_name.str.len, curr_gbl_name.str.addr,
-										LEN_AND_LIT("\"#CYCLE\""),
-										ERR_TEXT, 2,
-										RTS_ERROR_TEXT("#CYCLE field is missing"));
-							}
-						}
-						mv_cycle_ptr = &trigger_cycle;
-						cycle = MV_FORCE_INT(mv_cycle_ptr);
-						/* kill ^#t(curr_gbl_name) */
-						BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
-						gvcst_kill(TRUE);
-						cycle++;
-						MV_FORCE_MVAL(&trigger_cycle, cycle);
-						/* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
-						SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
-							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
-						assert(PUT_SUCCESS == result);
-					} /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
-					/* get ready for op_gvorder() call for next trigger under ^#t */
-					BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
-			}
+				/* Now that we know there is something to kill, check if we have permissions to touch ^#t global */
+				if (reg->read_only)
+					rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
+				mv_count_ptr = &trigger_count;
+				count = MV_FORCE_UINT(mv_count_ptr);
+				/* $get(^#t(curr_gbl_name,#CYCLE)) */
+				BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+					LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
+				if (!gvcst_get(&trigger_cycle))
+				{	/* Found #COUNT, there must be #CYCLE */
+					if (CDB_STAGNATE > t_tries)
+						t_retry(cdb_sc_triggermod);
+					assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+					rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
+							curr_gbl_name.str.len, curr_gbl_name.str.addr,
+							curr_gbl_name.str.len, curr_gbl_name.str.addr, LEN_AND_LIT("\"#CYCLE\""),
+							ERR_TEXT, 2, RTS_ERROR_TEXT("#CYCLE field is missing"));
+				}
+				mv_cycle_ptr = &trigger_cycle;
+				cycle = MV_FORCE_UINT(mv_cycle_ptr);
+				if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+				{
+					jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+					jnl_format_done = TRUE;
+				}
+				/* kill ^#t(curr_gbl_name) */
+				BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
+				gvcst_kill(TRUE);
+				/* Note : ^#t(curr_gbl_name,"#TRHASH") is also killed as part of the above */
+				cycle++;
+				MV_FORCE_MVAL(&trigger_cycle, cycle);
+				/* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
+				SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
+					LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
+				assert(PUT_SUCCESS == result);
+				this_db_updated = TRUE;
+				triggers_deleted += count;
+			} /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
+			/* get ready for op_gvorder() call for next trigger under ^#t */
+			BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
+		}
+		if (this_db_updated)
+		{
 			csa->incr_db_trigger_cycle = TRUE;
 			if (dollar_ztrigger_invoked)
 			{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
@@ -874,6 +862,28 @@ void trigger_delete_all(char *trigger_rec, uint4 len)
 			}
 		}
 	}
-	util_out_print_gtmio("All existing triggers deleted", FLUSH);
+	if (!jnl_format_done && (NULL != lgtrig_reg))
+	{	/* There was no journaled region that had a ^#t update, but found at least one journaled region
+		 * so write a LGTRIG logical jnl record there.
+		 */
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
+		csa = cs_addrs;
+		JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);	/* see previous usage for comment on why it is needed */
+		assert(dollar_tlevel);
+		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
+									 * even if NO db updates happen to ^#t nodes. */
+		jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+		jnl_format_done = TRUE;
+	}
+	if (triggers_deleted)
+	{
+		util_out_print_gtmio("All existing triggers (count = !UL) deleted", FLUSH, triggers_deleted);
+		trig_stats[STATS_DELETED] += triggers_deleted;
+		trig_stats[STATS_NOERROR_TRIGFILE]++;
+	} else
+	{
+		util_out_print_gtmio("No matching triggers found for deletion", FLUSH);
+		trig_stats[STATS_UNCHANGED_TRIGFILE]++;
+	}
 }
 #endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_delete_protos.h b/sr_unix/trigger_delete_protos.h
index 61c7934..98a0105 100644
--- a/sr_unix/trigger_delete_protos.h
+++ b/sr_unix/trigger_delete_protos.h
@@ -12,15 +12,15 @@
 #ifndef MU_TRIG_DELETE_PROTOS_H_INCLUDED
 #define MU_TRIG_DELETE_PROTOS_H_INCLUDED
 
-STATICFNDCL void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
+void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
 		stringkey *kill_hash, boolean_t del_kill_hash, int match_index);
-STATICFNDCL void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len);
+void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, int trigger_name_len);
 STATICFNDCL int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **values, uint4 *value_len, stringkey *set_hash,
 					   stringkey *kill_hash, int old_trig_index, int new_trig_index);
-STATICFNDCL int4 update_trigger_name_value(int trigvn_len, char *trig_name, int trig_name_len, int new_trig_index);
+STATICFNDCL int4 update_trigger_name_value(char *trig_name, int trig_name_len, int new_trig_index);
 
 boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats);
 int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index);
-void trigger_delete_all(char *trigger_rec, uint4 len);
+void trigger_delete_all(char *trigger_rec, uint4 len, uint4 *trig_stats);
 
 #endif
diff --git a/sr_unix/trigger_fill_xecute_buffer.c b/sr_unix/trigger_fill_xecute_buffer.c
index 2541dd5..182789e 100644
--- a/sr_unix/trigger_fill_xecute_buffer.c
+++ b/sr_unix/trigger_fill_xecute_buffer.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -23,7 +23,7 @@
 #include "mv_stent.h"			/* for COPY_SUBS_TO_GVCURRKEY macro */
 #include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
 #include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL */
 #include "filestruct.h"			/* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
 #include "mvalconv.h"
 #include "gdscc.h"			/* needed for tp.h */
@@ -42,6 +42,7 @@
 #include "gtmimagename.h"
 #include "trigger_fill_xecute_buffer.h"
 #include "trigger_gbl_fill_xecute_buffer.h"
+#include "gtm_trigger_trc.h"
 
 GBLREF	sgmnt_data_ptr_t	cs_data;
 GBLREF	sgmnt_addrs		*cs_addrs;
@@ -55,8 +56,6 @@ GBLREF	int4			tstart_trigger_depth;
 GBLREF	int4			gtm_trigger_depth;
 GBLREF	tp_frame		*tp_pointer;
 
-LITREF	mval			literal_hasht;
-
 error_def(ERR_TRIGNAMBAD);
 error_def(ERR_TPRETRY);
 
@@ -112,10 +111,12 @@ int trigger_fill_xecute_buffer(gv_trigger_t *trigdsc)
 		|| (tp_pointer->implicit_tstart && tp_pointer->implicit_trigger
 		&& (tstart_trigger_depth != gtm_trigger_depth)))	/* Case 3 */
 	{	/* Test for Case 3/4 where we get to do very little: */
+		DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 2/3\n"));
 		assert((!tp_pointer->implicit_trigger) || (0 < gtm_trigger_depth));
 		trigger_fill_xecute_buffer_read_trigger_source(trigdsc);
 	} else
 	{	/* Test for Case 1 where we only need a condition handler */
+		DBGTRIGR((stderr, "trigger_fill_xecute_buffer: Case 1\n"));
 		assert(tp_pointer->implicit_tstart && tp_pointer->implicit_trigger);
 		assert(tstart_trigger_depth == gtm_trigger_depth);
 		ESTABLISH_RET(trigger_fill_xecute_buffer_ch, SIGNAL);
@@ -151,6 +152,8 @@ STATICFNDEF void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *tr
 	gvt_trigger = trigdsc->gvt_trigger;			/* We now know our base block now */
 	index = trigdsc - gvt_trigger->gv_trig_array + 1;	/* We now know our trigger index value */
 	i2mval(&trig_index, index);
+	DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: entry $tlevel:%d\tindex:%d of %d\n",
+				dollar_tlevel, index, gvt_trigger->num_gv_triggers));
 	gvt = gv_target = gvt_trigger->gv_target;		/* gv_target contains global name */
 	gbl.addr = gvt->gvname.var_name.addr;
 	gbl.len = gvt->gvname.var_name.len;
@@ -175,6 +178,7 @@ STATICFNDEF void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *tr
 		 * updater on the secondary so we dont expect it to see any concurrent trigger changes
 		 * Assert accordingly.
 		 */
+		DBGTRIGR((stderr, "trigger_fill_xecute_buffer_read_trigger_source: stale trigger view\n"));
 		assert(CDB_STAGNATE > t_tries);
 		assert(IS_GTM_IMAGE);
 		t_retry(cdb_sc_triggermod);
diff --git a/sr_unix/trigger_gbl_fill_xecute_buffer.c b/sr_unix/trigger_gbl_fill_xecute_buffer.c
index b120082..e719300 100644
--- a/sr_unix/trigger_gbl_fill_xecute_buffer.c
+++ b/sr_unix/trigger_gbl_fill_xecute_buffer.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -24,11 +24,13 @@
 #include "op.h"
 #include "trigger.h"
 #include "trigger_gbl_fill_xecute_buffer.h"
+#include "gtm_trigger_trc.h"
 #include "mvalconv.h"
 #include "memcoherency.h"
 #include "t_retry.h"
 #include "gtmimagename.h"
 #include "filestruct.h"			/* for FILE_INFO, needed by REG2CSA */
+#include "have_crit.h"
 
 LITREF	mval			literal_ten;
 
@@ -47,6 +49,8 @@ GBLREF	gv_key			*gv_currkey;
 GBLREF	uint4			dollar_tlevel;
 GBLREF	unsigned int		t_tries;
 
+LITREF	char			*trigger_subs[];
+
 STATICDEF char			*xecute_buff;
 
 STATICFNDCL CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch);
@@ -66,7 +70,6 @@ STATICFNDEF CONDITION_HANDLER(trigger_gbl_fill_xecute_buffer_ch)
 char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_index, mval *first_rec, int4 *xecute_len)
 {
 	mval			data_val;
-	boolean_t		have_value;
 	mval			index, key_val, *val_ptr;
 	int4			len, xecute_buff_len;
 	int4			num;
@@ -80,32 +83,41 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	/* assert(0 < dollar_tlevel); Too be added later when it stops breaking MUPIP SELECT & $ZTRIGGER("SELECT"..) */
+	assert(0 < dollar_tlevel); /* Too be added later when it stops breaking MUPIP SELECT & $ZTRIGGER("SELECT"..) */
 	xecute_buff = NULL;
 	ESTABLISH_RET(trigger_gbl_fill_xecute_buffer_ch, NULL);
 	index = *trig_index;
+	DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: entry $tlevel:%d\tindex:%d\t:crit:%d\tkv:%d\n",
+				dollar_tlevel, mval2i(&index), have_crit(CRIT_HAVE_ANY_REG), key_val.str.len));
 	if (NULL != first_rec)
 	{
+		DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: NULL != first_rec\n"));
 		xecute_buff_len = first_rec->str.len;
 		assert(MAX_XECUTE_LEN >= xecute_buff_len);
 		xecute_buff = malloc(xecute_buff_len);
 		memcpy(xecute_buff, first_rec->str.addr, xecute_buff_len);
 	} else
 	{	/* First check for a single record xecute string */
-		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN);
-		if (gvcst_get(&data_val))
+		DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: First check for a single record xecute string\n"));
+		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, index,
+					trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]));
+		if (gvcst_get(&key_val))
 		{
-			xecute_buff_len = data_val.str.len;
+			xecute_buff_len = key_val.str.len;
 			assert(MAX_XECUTE_LEN >= xecute_buff_len);
 			xecute_buff = malloc(xecute_buff_len);
-			memcpy(xecute_buff, data_val.str.addr, xecute_buff_len);
+			memcpy(xecute_buff, key_val.str.addr, xecute_buff_len);
 			*xecute_len = xecute_buff_len;
+			DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: Found a single record xecute string of %d bytes\n",
+						xecute_buff_len));
 			REVERT;
 			return xecute_buff;
 		} else
 		{	/* No single line trigger exists. See if multi-line trigger exists. The form is ^#t(gbl,indx,XECUTE,n)
 			 * so can be easily tested for with $DATA().
 			 */
+			DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: No single record xecute string(%d), try for multiline\n",
+						key_val.str.len));
 			op_gvdata(&data_val);
 			if ((literal_ten.m[0] != data_val.m[0]) || (literal_ten.m[1] != data_val.m[1]))
 			{	/* The process' view of the triggers is likely stale. Restart to be safe.
@@ -114,8 +126,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
 				 * updater on the secondary so we dont expect it to see any concurrent trigger changes
 				 * Assert accordingly. Note similar asserts occur in t_end.c and tp_tend.c.
 				 */
-				assert(CDB_STAGNATE > t_tries);
 				assert(IS_GTM_IMAGE);
+				DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: multiline not found, retry\n"));
 				/* Assert that the cycle has changed but in order to properly do the assert, we need a memory
 				 * barrier since cs_data->db_trigger_cycle could be stale in our cache.
 				 */
@@ -124,16 +136,26 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
 				DEBUG_ONLY(gvt_cycle = gv_target->db_trigger_cycle);
 				DEBUG_ONLY(csd_cycle = cs_data->db_trigger_cycle);
 				assert(csd_cycle > gvt_cycle);
-				t_retry(cdb_sc_triggermod);
+				if (CDB_STAGNATE > t_tries)
+					t_retry(cdb_sc_triggermod);
+				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+				trgindx = mval2i(&index);
+				SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
+				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+						trigvn_len, trigvn, util_len, util_buff);
 			}
 		}
 		/* Multi-line triggers exist */
 		num = 0;
 		i2mval(&xecute_index, num);
-		BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN, xecute_index);
+		BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index,
+					trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]), xecute_index);
 		if (!gvcst_get(&key_val))
-		{	/* There has to be an XECUTE string */
-			assert(FALSE);
+		{	/* There has to be an XECUTE string or else it is a retry situation (due to concurrent updates) */
+			DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: problem getting multiline record count, retry\n"));
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
 			trgindx = mval2i(&index);
 			SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
 			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
@@ -147,14 +169,19 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
 		while (len < xecute_buff_len)
 		{
 			i2mval(&xecute_index, ++num);
-			BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index, LITERAL_XECUTE, LITERAL_XECUTE_LEN,
-				xecute_index);
+			BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, index,
+					trigger_subs[XECUTE_SUB], STRLEN(trigger_subs[XECUTE_SUB]), xecute_index);
 			if (!gvcst_get(&key_val))
 				break;
 			if (xecute_buff_len < (len + key_val.str.len))
-			{	/* The DB string total is longer than the length stored at index 0 -- something is wrong */
+			{	/* The DB string total is longer than the length stored at index 0 -- something is wrong.
+				 * Most likely a retry necessary due to concurrent changes.
+				 */
+				DBGTRIGR((stderr, "trigger_gbl_fill_xecute_buffer: problem getting multiline component, retry\n"));
 				free(xecute_buff);
-				assert(FALSE);
+				if (CDB_STAGNATE > t_tries)
+					t_retry(cdb_sc_triggermod);
+				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
 				SET_PARAM_STRING(util_buff, util_len, num, ",\"XECUTE\"");
 				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
 						trigvn_len, trigvn, util_len, util_buff);
diff --git a/sr_unix/trigger_parse.c b/sr_unix/trigger_parse.c
index e5be210..b742197 100644
--- a/sr_unix/trigger_parse.c
+++ b/sr_unix/trigger_parse.c
@@ -530,12 +530,21 @@ boolean_t check_trigger_name(char *name_str, uint4 *name_len)
 	 */
 	lcl_name_len = *name_len;
 	if (MAX_USER_TRIGNAME_LEN < lcl_name_len)
+	{
+		util_out_print_gtmio("Trigger name length [!UL] exceeds maximum supported length of [!UL]",
+			FLUSH, lcl_name_len, MAX_USER_TRIGNAME_LEN);
 		return FALSE;
+	}
 	ptr = (unsigned char *)name_str;
 	if (('%' != *ptr) && !ISALPHA_ASCII(*ptr))
+	{
+		util_out_print_gtmio("Trigger name does not begin with an ascii alphabet or %", FLUSH);
 		return FALSE;
+	}
 	for (len = lcl_name_len - 1, ptr++; (0 < len) && ISALNUM_ASCII(*ptr); ptr++, len--)
 	    	;
+	if (len)
+		util_out_print_gtmio("Trigger name has non-alphanumeric character", FLUSH);
 	return (0 == len);
 }
 
@@ -592,7 +601,7 @@ STATICFNDEF boolean_t process_options(char *option_str, uint4 option_len, boolea
 				}
 				break;
 			default:
-				assertpro(FALSE);	/* Parsing should have found invalid command */
+				assert(FALSE);	/* Parsing should have found invalid command */
 				break;
 		}
 	} while (ptr = strtok(NULL, ","));
@@ -1231,7 +1240,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		if ((XTENDED_STOP_LEN != input_len) || (0 != memcmp(XTENDED_STOP, input, XTENDED_STOP_LEN)))
 		{
 			ptr1 = values[XECUTE_SUB] + value_len[XECUTE_SUB];
-			if (0 < (max_output_len - input_len - 1))
+			if ((input_len + 1) < max_output_len)
 			{
 				memcpy(ptr1, input, input_len);
 				ptr1 += input_len;
@@ -1243,7 +1252,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 			} else
 			{
 				*multi_line_xecute = FALSE;
-				util_out_print_gtmio("Trigger definition too long", FLUSH);
+				util_out_print_gtmio("Error : Trigger definition too long", FLUSH);
 				return FALSE;
 			}
 		}
@@ -1251,7 +1260,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], TRUE))
 		{
 			*multi_line_xecute = FALSE;
-			ERROR_MSG_RETURN("Error parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
+			ERROR_MSG_RETURN("Error : Parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
 		}
 		*multi_line_xecute = out_multi_line_xecute;
 		*max_len = max_output_len;
@@ -1261,20 +1270,20 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 	len = (uint4)input_len;
 	if ('^' != *ptr1++)
 	{
-		ERROR_MSG_RETURN("Missing global name:\n", input_len, input);
+		ERROR_MSG_RETURN("Error : Missing global name:\n", input_len, input);
 	}
 	ptr = ptr1;
 	len--;
 	if (('%' != *ptr1) && !ISALPHA_ASCII(*ptr1))
 	{
-		ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
+		ERROR_MSG_RETURN("Error : Invalid global name:\n", input_len, input);
 	}
 	ptr1++;
 	while (ISALNUM_ASCII(*ptr1))
 		ptr1++;
 	if (('(' != *ptr1) && !ISSPACE_ASCII(*ptr1))
 	{
-		ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
+		ERROR_MSG_RETURN("Error : Invalid global name:\n", input_len, input);
 	}
 	trigvn_len = (int)(ptr1 - ptr);
 	if (MAX_MIDENT_LEN < trigvn_len)
@@ -1299,7 +1308,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		len = 0;
 	if (0 > --max_output_len)
 	{
-		util_out_print_gtmio("Trigger definition too long", FLUSH);
+		util_out_print_gtmio("Error : Trigger definition too long", FLUSH);
 		return TRIG_FAILURE;
 	}
 	values[GVSUBS_SUB][len] = '\0';
@@ -1313,7 +1322,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 	cmd_ary = save_cmd_ary;
 	if (parse_ret)
 	{
-		ERROR_MSG_RETURN("Parse error in input:\n", input_len, input);
+		ERROR_MSG_RETURN("Error : In parsing input:\n", input_len, input);
 	}
 	values[CMD_SUB] = values[GVSUBS_SUB] + value_len[GVSUBS_SUB] + 1;
 	if (CLI_PRESENT == cli_present("COMMANDS"))
@@ -1353,7 +1362,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		if (CLI_PRESENT == cli_present("COMMANDS.ZTKILL"))
 		{
 			if (found_kill)
-				ERROR_MSG_RETURN("KILL and ZTKILL incompatible: ", value_len[CMD_SUB], values[CMD_SUB]);
+				ERROR_MSG_RETURN("Error : KILL and ZTKILL incompatible: ", value_len[CMD_SUB], values[CMD_SUB]);
 			ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
 			ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.len,
 				gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.addr, max_output_len);
@@ -1370,9 +1379,9 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		value_len[CMD_SUB] = 0;
 	UPDATE_TRIG_PTRS(values[CMD_SUB], values[DELIM_SUB], value_len[CMD_SUB], max_output_len);
 	GET_CLI_STR_AND_CHECK("DELIM", delim_present, max_output_len, process_delim, values[DELIM_SUB], value_len[DELIM_SUB],
-			      values[TRIGNAME_SUB], "Error parsing DELIM string: ");
+			      values[TRIGNAME_SUB], "Error : Parsing DELIM string: ");
 	GET_CLI_STR_AND_CHECK("NAME", name_present, max_output_len, check_trigger_name, values[TRIGNAME_SUB],
-			      value_len[TRIGNAME_SUB], values[OPTIONS_SUB], "Error parsing NAME string: ");
+			      value_len[TRIGNAME_SUB], values[OPTIONS_SUB], "Error : Parsing NAME string: ");
 	if (CLI_PRESENT == cli_present("OPTIONS"))
 	{
 		boolean_t	isolation, noisolation, consistency, noconsistency;
@@ -1381,7 +1390,8 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		if (!process_options(values[OPTIONS_SUB], value_len[OPTIONS_SUB], &isolation, &noisolation, &consistency,
 				&noconsistency))
 		{
-			ERROR_MSG_RETURN("Inconsistent values in OPTIONS string: ", value_len[OPTIONS_SUB], values[OPTIONS_SUB]);
+			ERROR_MSG_RETURN("Error : Inconsistent values in OPTIONS string: ",
+				value_len[OPTIONS_SUB], values[OPTIONS_SUB]);
 		}
 		count = 0;
 		ptr = values[OPTIONS_SUB];
@@ -1411,7 +1421,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 	GET_CLI_STR_AND_CHECK("PIECES", pieces_present, max_output_len, process_pieces, values[PIECES_SUB], value_len[PIECES_SUB],
 			      values[ZDELIM_SUB], "");
 	GET_CLI_STR_AND_CHECK("ZDELIM", zdelim_present, max_output_len, process_delim, values[ZDELIM_SUB], value_len[ZDELIM_SUB],
-			      values[XECUTE_SUB], "Error parsing ZDELIM string: ");
+			      values[XECUTE_SUB], "Error : Parsing ZDELIM string: ");
 	/* Since process_xecute() does a test compile of the xecute string, it changes the parsing table from MUPIP TRIGGER
 	 * to GT.M.  To avoid problems with saving and restoring the parse state (which would have to be done with globals
 	 * that are static in cli_parse.c), it is much easier to put process_xecute() last in the list of qualifiers to check -
@@ -1426,7 +1436,7 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		{
 			ptr = values[XECUTE_SUB];
 			len = value_len[XECUTE_SUB];
-			ERROR_MSG_RETURN("Error parsing XECUTE string: ", len, ptr);
+			ERROR_MSG_RETURN("Error : Parsing XECUTE string: ", len, ptr);
 		}
 	} else
 		value_len[XECUTE_SUB] = 0;
@@ -1438,28 +1448,28 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value
 		*ptr = '\0';
 		if (!xecute_present && !out_multi_line_xecute)
 		{
-			ERROR_STR_RETURN("XECUTE value missing");
+			ERROR_STR_RETURN("Error: XECUTE value missing");
 		}
 		if (0 == value_len[CMD_SUB])
 		{
-			ERROR_STR_RETURN("COMMANDS value missing");
+			ERROR_STR_RETURN("Error: COMMANDS value missing");
 		}
 		if (delim_present && zdelim_present)
 		{
-			ERROR_STR_RETURN("Can't have both DELIM and ZDELIM in same entry");
+			ERROR_STR_RETURN("Error: Can't have both DELIM and ZDELIM in same entry");
 		}
 		if ((delim_present || zdelim_present) && !set_present)
 		{
-			ERROR_STR_RETURN("DELIM and ZDELIM need a commands=SET");
+			ERROR_STR_RETURN("Error: DELIM and ZDELIM need a commands=SET");
 		}
 		if (pieces_present && (!delim_present && !zdelim_present))
 		{
-			ERROR_STR_RETURN("PIECES need either DELIM or ZDELIM");
+			ERROR_STR_RETURN("Error: PIECES need either DELIM or ZDELIM");
 		}
 		if (MAX_HASH_INDEX_LEN < (trigvn_len + 1 + value_len[GVSUBS_SUB] + 1 + value_len[DELIM_SUB] + 1
 					  + value_len[ZDELIM_SUB] + 1 + value_len[XECUTE_SUB] + 1))
 		{
-			ERROR_STR_RETURN("Entry too large to properly index");
+			ERROR_STR_RETURN("Error: Entry too large to properly index");
 		}
 	}
 	*multi_line_xecute = out_multi_line_xecute;
diff --git a/sr_unix/trigger_read_name_entry.c b/sr_unix/trigger_read_name_entry.c
deleted file mode 100644
index be21fcc..0000000
--- a/sr_unix/trigger_read_name_entry.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- *								*
- *	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"
-
-#ifdef GTM_TRIGGER
-
-#include "gdsroot.h"			/* for gdsfhead.h */
-#include "gdsbt.h"			/* for gdsfhead.h */
-#include "gdsfhead.h"
-#include "gvcst_protos.h"
-#include <rtnhdr.h>
-#include "gv_trigger.h"
-#include "trigger.h"
-#include "trigger_read_name_entry.h"
-#include "mv_stent.h"			/* for COPY_SUBS_TO_GVCURRKEY macro */
-#include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
-#include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
-#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 "filestruct.h"			/* needed for jnl.h */
-#include "jnl.h"			/* needed for tp.h */
-#include "tp.h"				/* for sgm_info */
-
-GBLREF	sgmnt_data_ptr_t	cs_data;
-GBLREF	gd_region		*gv_cur_region;
-GBLREF	gv_key			*gv_currkey;
-GBLREF	sgm_info		*sgm_info_ptr;
-
-LITREF	mval			literal_hasht;
-
-boolean_t trigger_read_name_entry(mident *trig_name, mval *val)
-{
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
-	boolean_t		status;
-	DCL_THREADGBL_ACCESS;
-
-	SETUP_THREADGBL_ACCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	if (0 == gv_target->root)
-	{
-		RESTORE_TRIGGER_REGION_INFO(save_currkey);
-		return FALSE;
-	}
-	BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name->addr, trig_name->len - 1);
-	status = gvcst_get(val);
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
-	return status;
-}
-#endif
diff --git a/sr_unix/trigger_read_name_entry.h b/sr_unix/trigger_read_name_entry.h
deleted file mode 100644
index 228b9b5..0000000
--- a/sr_unix/trigger_read_name_entry.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/****************************************************************
- *								*
- *	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 TRIGGER_READ_NAME_ENTRY_H_INCLUDED
-#define TRIGGER_READ_NAME_ENTRY_H_INCLUDED
-
-boolean_t trigger_read_name_entry(mident *trig_name, mval *val);
-
-#endif
diff --git a/sr_unix/trigger_select.c b/sr_unix/trigger_select.c
index 43e6313..b2376ad 100644
--- a/sr_unix/trigger_select.c
+++ b/sr_unix/trigger_select.c
@@ -34,7 +34,7 @@
 #include "trigger_user_name.h"
 #include "change_reg.h"
 #include "gvcst_protos.h"
-#include "op.h"
+#include "op.h"			/* for op_tstart etc. */
 #include "mupip_exit.h"
 #include "zshow.h"
 #include "util.h"
@@ -54,6 +54,8 @@
 #include "gtmio.h"
 #include "have_crit.h"
 #include "hashtab_mname.h"
+#include "tp_frame.h"
+#include "tp_restart.h"
 
 GBLREF	sgmnt_addrs		*cs_addrs;
 GBLREF	sgmnt_data_ptr_t	cs_data;
@@ -66,8 +68,12 @@ GBLREF	io_pair			io_curr_device;
 GBLREF	io_pair			io_std_device;			/* standard device */
 GBLREF	sgm_info		*sgm_info_ptr;
 GBLREF	int			(*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
+GBLREF	uint4			dollar_tlevel;
+GBLREF	unsigned char		t_fail_hist[CDB_MAX_TRIES];
+#ifdef DEBUG
+GBLREF	boolean_t		donot_INVOKE_MUMTSTART;
+#endif
 
-LITREF	mval		    	literal_hasht;
 LITREF	mval			literal_zero;
 LITREF	mval			literal_ten;
 LITREF	char 			*trigger_subs[];
@@ -77,20 +83,22 @@ LITREF	char 			*trigger_subs[];
 
 #define NAM_LEN(PTR, LEN)	MIN(STRLEN((PTR)), (LEN))
 
-#define COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(OUT_BUFF, OUT_PTR, VAL, VAL_LEN)		\
-{											\
-	mval		op_val;								\
-											\
-	assert(MAX_BUFF_SIZE >= VAL_LEN);						\
-	if ((INTCAST(OUT_PTR - OUT_BUFF) + VAL_LEN) > MAX_BUFF_SIZE)			\
-	{										\
-		STR2MVAL(op_val, OUT_BUFF, (unsigned int)(OUT_PTR - OUT_BUFF));		\
-		op_write(&op_val);							\
-		io_curr_device.out->dollar.x = 0;					\
-		OUT_PTR = OUT_BUFF;							\
-	}										\
-	memcpy(OUT_PTR, (const void *)VAL, VAL_LEN);					\
-	OUT_PTR += VAL_LEN;								\
+#define COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(OUT_BUFF, OUT_PTR, VAL, VAL_LEN)				\
+{													\
+	if ((INTCAST(OUT_PTR - OUT_BUFF) + VAL_LEN) > MAX_BUFF_SIZE)					\
+	{												\
+		util_out_print_gtmio("!AD", NOFLUSH, (unsigned int)(OUT_PTR - OUT_BUFF), OUT_BUFF);	\
+		OUT_PTR = OUT_BUFF;									\
+	}												\
+	if (VAL_LEN > MAX_BUFF_SIZE)									\
+	{												\
+		util_out_print_gtmio("!AD", NOFLUSH, VAL_LEN, VAL);					\
+		OUT_PTR = OUT_BUFF;									\
+	} else												\
+	{												\
+		memcpy(OUT_PTR, (const void *)VAL, VAL_LEN);						\
+		OUT_PTR += VAL_LEN;									\
+	}												\
 }
 
 #define COPY_SUBSCRIPT(OUT_BUFF, OUT_PTR, CHPTR, LEN_LEFT, IS_TYPE)			\
@@ -149,14 +157,19 @@ LITREF	char 			*trigger_subs[];
 	select_status = TRIG_FAILURE;							\
 }
 
+error_def(ERR_DBROLLEDBACK);
+error_def(ERR_MUNOACTION);
 error_def(ERR_MUNOACTION);
 error_def(ERR_MUPCLIERR);
-error_def(ERR_TRIGDEFBAD);
 error_def(ERR_MUPCLIERR);
-error_def(ERR_MUNOACTION);
-
+error_def(ERR_NEEDTRIGUPGRD);
+error_def(ERR_TRIGDEFBAD);
 
-STATICDEF char *triggerfile_quals[] = {"-name=", "", "-commands=", "-options=", "-delim=", "-zdelim=", "-pieces=", "-xecute="};
+STATICDEF char *triggerfile_quals[] = {
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	TRIGFILEQUAL,
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
+};
 
 STATICFNDEF void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr, int *sub_len)
 {
@@ -195,7 +208,7 @@ STATICFNDEF void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr,
 	*out_ptr = out_p;
 }
 
-STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, int nam_indx)
+STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, int nam_indx)
 {
 	mval			data_val;
 	char			out_rec[MAX_BUFF_SIZE];
@@ -220,6 +233,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	assert(!cs_addrs->hdr->hasht_upgrade_needed);	/* all callers should have errored out otherwise */
 	BUILD_HASHT_SUB_SUB_CURRKEY(gbl_name, gbl_name_len, LITERAL_HASHCOUNT, LITERAL_HASHCOUNT_LEN);
 	if (gvcst_get(&trigger_count))
 	{
@@ -228,12 +242,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 		{	/* There has to be a #LABEL */
 			if (CDB_STAGNATE > t_tries)
 				t_retry(cdb_sc_triggermod);
-			else
-			{
-				assert(FALSE);
-				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
-						gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#LABEL\""));
-			}
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+					gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#LABEL\""));
 		}
 		skip_chars = 1;
 		if ((trigger_value.str.len != STRLEN(HASHT_GBL_CURLABEL))
@@ -250,12 +261,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 		{	/* There has to be a #CYCLE */
 			if (CDB_STAGNATE > t_tries)
 				t_retry(cdb_sc_triggermod);
-			else
-			{
-				assert(FALSE);
-				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
-						gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#CYCLE\""));
-			}
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+					gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#CYCLE\""));
 		}
 		assert(MAX_DIGITS_IN_INT >= trigger_value.str.len);
 		memcpy(cycle, trigger_value.str.addr, trigger_value.str.len);
@@ -269,21 +277,29 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(gbl_name, gbl_name_len, mi, trigger_subs[TRIGNAME_SUB],
 				STRLEN(trigger_subs[TRIGNAME_SUB]));
 			out_rec_ptr = out_rec;
-			if (gvcst_get(&trigger_value))
-			{
-				*out_rec_ptr++ = COMMENT_LITERAL;
+			if (!gvcst_get(&trigger_value))
+			{	/* There has to be a #NAME */
+				if (CDB_STAGNATE > t_tries)
+					t_retry(cdb_sc_triggermod);
+				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len,
+						gbl_name, gbl_name_len, gbl_name, LEN_AND_LIT("\"#NAME\""));
 
-				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_NAME_COMMENT,
-					STR_LIT_LEN(TRIGGER_NAME_COMMENT));
-				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, trigger_value.str.addr,
-					trigger_value.str.len);
-				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_CYCLE_COMMENT,
-					STR_LIT_LEN(TRIGGER_CYCLE_COMMENT));
-				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, cycle, STRLEN(cycle));
-				STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
-				op_write(op_val);
-				op_wteol(1);
 			}
+			*out_rec_ptr++ = COMMENT_LITERAL;
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_NAME_COMMENT,
+				STR_LIT_LEN(TRIGGER_NAME_COMMENT));
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, trigger_value.str.addr,
+				trigger_value.str.len - 1);	/* remove last # in name */
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, SPANREG_REGION_LIT,
+				SPANREG_REGION_LITLEN);
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, gv_cur_region->rname,
+				gv_cur_region->rname_len);
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ")", 1);
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, TRIGGER_CYCLE_COMMENT,
+				STR_LIT_LEN(TRIGGER_CYCLE_COMMENT));
+			COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, cycle, STRLEN(cycle));
+			util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
 			out_rec_ptr = out_rec;
 			*out_rec_ptr++ = '+';
 			*out_rec_ptr++ = '^';
@@ -298,6 +314,11 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 				write_subscripts(out_rec, &out_rec_ptr, &sub_ptr, &sub_len);
 				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ")", 1);
 			}
+			/* Assert that BHASH and LHASH are not part of NUM_SUBS calculation
+			 * (confirms the -2 done in the #define of NUM_SUBS).
+			 */
+			assert(BHASH_SUB == NUM_SUBS);
+			assert(LHASH_SUB == (NUM_SUBS + 1));
 			for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
 			{
 				if ((GVSUBS_SUB == sub_indx) || (CHSET_SUB == sub_indx))
@@ -305,6 +326,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(gbl_name, gbl_name_len, mi, trigger_subs[sub_indx],
 					STRLEN(trigger_subs[sub_indx]));
 				have_value = gvcst_get(&trigger_value);
+				have_value = have_value && (trigger_value.str.len);
 				multi_record = FALSE;
 				if (!have_value && (XECUTE_SUB == sub_indx))
 				{
@@ -314,7 +336,7 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 				if (have_value || multi_record)
 				{
 					if (TRIGNAME_SUB == sub_indx)
-					{	/* Output name only if it is user defined */
+					{	/* Output "-name=XYZ" only if it is user defined */
 						BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(gbl_name, gbl_name_len, mi,
 							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), mi);
 						if (!trigger_user_name(trigger_value.str.addr, trigger_value.str.len))
@@ -360,11 +382,9 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 					}
 				}
 			}
-			/* we had better have an XECUTE STRING, probably should check some buddies */
-			assert(NULL != xecute_buff);
-			STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
-			op_write(op_val);
-			op_wteol(1);
+			/* we had better have an XECUTE STRING, if not it is a restartable situation */
+			DEBUG_ONLY(if (NULL == xecute_buff) TREF(donot_commit) |= DONOTCOMMIT_TRIGGER_SELECT_XECUTE;)
+			util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
 			if (multi_line)
 			{
 				ptr1 = xecute_buff;
@@ -377,16 +397,12 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 						ptr2 = ptrtop; /* if last line is not terminated by newline, make it so */
 					out_rec_ptr = out_rec;
 					COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, ptr1, UINTCAST(ptr2 - ptr1));
-					STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
-					op_write(op_val);
-					op_wteol(1);
+					util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
 					ptr1 = ptr2 + 1;
 				} while (ptr1 < ptrtop);
 				out_rec_ptr = out_rec;
 				COPY_TO_OUTPUT_AND_WRITE_IF_NEEDED(out_rec, out_rec_ptr, XTENDED_STOP, XTENDED_STOP_LEN);
-				STR2MVAL((*op_val), out_rec, (unsigned int)(out_rec_ptr - out_rec));
-				op_write(op_val);
-				op_wteol(1);
+				util_out_print_gtmio("!AD", FLUSH, (unsigned int)(out_rec_ptr - out_rec), out_rec);
 			}
 			if (NULL != xecute_buff)
 			{
@@ -397,42 +413,34 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
 	}
 }
 
-STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, boolean_t trig_name)
+STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, boolean_t trig_name)
 {
 	char			save_name[MAX_MIDENT_LEN], curr_name[MAX_MIDENT_LEN];
 	boolean_t		wildcard;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
-	mname_entry		ms_gvname;
 	mval			mv_curr_nam;
-        mval                    mi, trigger_count, trig_gbl;
-        mval                    *mv_trig_cnt_ptr, mv_trigger_val;
+        mval                    mi, trig_gbl;
+        mval                    mv_trigger_val;
 	int			indx, count;
-	char			*ptr;
+	char			*ptr, *ptr2;
 	uint4			curr_name_len;
 	int			trigvn_len;
-	gvnh_reg_t		*gvnh_reg;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	/* If ^#t needs to be upgraded, issue error. Cannot read older ^#t format that newer version does not always understand */
+	if (cs_addrs->hdr->hasht_upgrade_needed)
+		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
 	memcpy(save_name, gbl_name, gbl_name_len);
 	wildcard = (NULL != (ptr = memchr(gbl_name, '*', gbl_name_len)));
 	if (wildcard)
 	{
-		*ptr = '\0';
 		gbl_name_len--;
 		assert(INTCAST(ptr - gbl_name) == gbl_name_len);
 	}
-	mv_trig_cnt_ptr = &trigger_count;
 	memcpy(curr_name, gbl_name, gbl_name_len);
 	curr_name_len = gbl_name_len;
-	STR2MVAL(mv_curr_nam, gbl_name, gbl_name_len);
 	while (TRUE)
 	{
-		if (0 != memcmp(curr_name, save_name, gbl_name_len))
-			break;
 		if (trig_name)
 		{
 			BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
@@ -445,32 +453,34 @@ STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 f
 						break;
 					memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
 					curr_name_len = mv_curr_nam.str.len;
+					if (0 != memcmp(curr_name, save_name, gbl_name_len))
+						break;
 					continue;
 				}
 				break;
 			}
 			ptr = mv_trigger_val.str.addr;
-			trigvn_len = STRLEN(mv_trigger_val.str.addr);
-			ptr += trigvn_len + 1;
-			A2I(ptr, mv_trigger_val.str.addr + mv_trigger_val.str.len, indx);
+			ptr2 = memchr(ptr, '\0', mv_trigger_val.str.len);
+			if (NULL == ptr2)
+			{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+				if (CDB_STAGNATE > t_tries)
+					t_retry(cdb_sc_triggermod);
+				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6,
+						LEN_AND_LIT("\"#TNAME\""), curr_name_len, curr_name,
+						mv_trigger_val.str.len, mv_trigger_val.str.addr);
+			}
+			trigvn_len = ptr2 - ptr;
+			assert(('\0' == *ptr2) && (mv_trigger_val.str.len > trigvn_len));
+			ptr2++;
+			A2I(ptr2, mv_trigger_val.str.addr + mv_trigger_val.str.len, indx);
 			STR2MVAL(trig_gbl, mv_trigger_val.str.addr, trigvn_len);
-			SAVE_TRIGGER_REGION_INFO(save_currkey);
-			ms_gvname.var_name.addr = mv_trigger_val.str.addr;
-			ms_gvname.var_name.len = trigvn_len;
-			COMPUTE_HASH_MNAME(&ms_gvname);
-			GV_BIND_NAME_ONLY(gd_header, &ms_gvname, gvnh_reg);
-			SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
-			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
 		} else
 		{
 			STR2MVAL(trig_gbl, curr_name, curr_name_len);
 			indx = 0;
 		}
-		write_out_trigger(trig_gbl.str.addr, trig_gbl.str.len, file_name_len, op_val, indx);
-		if (trig_name)
-		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
-		}
+		write_out_trigger(trig_gbl.str.addr, trig_gbl.str.len, indx);
 		if (wildcard)
 		{
 			if (trig_name)
@@ -485,13 +495,15 @@ STATICFNDEF void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 f
 			if (0 == mv_curr_nam.str.len)
 				break;
 			memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
+			if (0 != memcmp(curr_name, save_name, gbl_name_len))
+				break;
 			curr_name_len = mv_curr_nam.str.len;
 		} else
 			break;
 	}
 }
 
-STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
+STATICFNDEF void dump_all_triggers(void)
 {
 	mval			curr_gbl_name, val;
 	gd_region		*reg;
@@ -509,17 +521,18 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
 	save_gvtarget = gv_target;
 	for (reg_index = 0, reg = gd_header->regions; reg_index < gd_header->n_regions; reg_index++, reg++)
 	{
-		if (!reg->open)
-			gv_init_reg(reg);
-		gv_cur_region = reg;
-		change_reg();
-		SET_GVTARGET_TO_HASHT_GBL(cs_addrs);
-		INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+		if (NULL == cs_addrs)	/* not MM or BG access method, which means GT.CM */
+			continue;
+		/* gv_target now points to ^#t in region "reg" */
 		if (0 != gv_target->root)
 		{
+			/* If ^#t needs to be upgraded, issue error. Cannot read older ^#t format */
+			if (cs_addrs->hdr->hasht_upgrade_needed)
+				rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
 			op_gvdata(&val);
 			if ((literal_ten.m[0] == val.m[0]) && (literal_ten.m[1] == val.m[1]))
-			{ /* $DATA(^#t) is 10 - get first subscript (trigger's global) */
+			{	/* $DATA(^#t) is 10 - get first subscript (trigger's global) */
 				BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STR_LIT_LEN(LITERAL_MAXHASHVAL));
 				while (TRUE)
 				{
@@ -528,7 +541,7 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
 						break;
 					gbl_len = curr_gbl_name.str.len;
 					memcpy(global, curr_gbl_name.str.addr, gbl_len);
-					write_out_trigger(global, gbl_len, file_name_len, op_val, 0);
+					write_out_trigger(global, gbl_len, 0);
 					BUILD_HASHT_SUB_CURRKEY(global, gbl_len);
 				}
 			} else
@@ -537,26 +550,16 @@ STATICFNDEF void dump_all_triggers(uint4 file_name_len, mval *op_val)
 	}
 }
 
-boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len)
+/* returns TRUE (not TRIG_FAILURE) in case of failure */
+boolean_t trigger_select_tpwrap(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len)
 {
-	char			*sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2;
-	int			gbl_len, prev_len;
-	mname_entry		gvname;
-	gv_namehead		*save_gvtarget;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	char			save_select_list[MAX_BUFF_SIZE];
-	mval			trigger_value;
-	int			len, len1, badpos;
-	int			local_errno;
-	boolean_t		trig_name;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
-	boolean_t		dump_all;
 	mval			op_val, op_pars;
 	boolean_t		select_status;
 	io_pair			save_io_curr_device;
-	gvnh_reg_t		*gvnh_reg;
+	mval			ts_mv;
+	int			loopcnt;
+	DEBUG_ONLY(unsigned int	lcl_t_tries;)
+	enum cdb_sc		failure;
 
 	static readonly unsigned char	open_params_list[] =
 	{
@@ -572,15 +575,13 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
 		(unsigned char)iop_eol
 	};
 	static readonly unsigned char	no_param = (unsigned char)iop_eol;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	/* make a local copy of the select list and use it to avoid string-pool problems */
 	if (MAX_BUFF_SIZE <= select_list_len)
-		return TRIG_FAILURE;
-	memcpy(save_select_list, select_list, select_list_len);
-	save_select_list[select_list_len] = '\0';
+		return TRUE;	/* failure return */
 	gvinit();
-	dump_all = FALSE;
-	prev_len = 0;
 	op_pars.mvtype = MV_STR;
 	op_val.mvtype = MV_STR;
 	if (0 == file_name_len)
@@ -608,13 +609,130 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
 	}
 	save_io_curr_device = io_curr_device;
 	op_use(&op_val, &op_pars);
+	TREF(ztrig_use_io_curr_device) = TRUE;
+	select_status = TRIG_SUCCESS;
+	ts_mv.mvtype = MV_STR;
+	ts_mv.str.len = 0;
+	ts_mv.str.addr = NULL;
+	if (0 == dollar_tlevel)
+	{	/* If not already wrapped in TP, wrap it now implicitly */
+		assert(!donot_INVOKE_MUMTSTART);
+		DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE);
+		/* Note down dollar_tlevel before op_tstart. This is needed to determine if we need to break from the for-loop
+		 * below after a successful op_tcommit of the trigger select . We cannot check that dollar_tlevel is zero
+		 * since the op_tstart done below can be a nested sub-transaction
+		 */
+		op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+		/* The following for loop structure is similar to that in function "trigger_trgfile_tpwrap" and various
+		 * other places so any changes here might need to be reflected there as well.
+		 */
+		for (loopcnt = 0; ; loopcnt++)
+		{
+			assert(donot_INVOKE_MUMTSTART);	/* Make sure still set */
+			DEBUG_ONLY(lcl_t_tries = t_tries);
+			select_status = trigger_select_tpwrap_helper(select_list, select_list_len);
+			if (0 == dollar_tlevel)
+				break;
+			assert(0 < t_tries);
+			assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1));
+			failure = LAST_RESTART_CODE;
+			assert(((cdb_sc_onln_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure))
+				|| !gv_target || !gv_target->root);
+			assert((cdb_sc_onln_rlbk2 != failure) || !IS_GTM_IMAGE || TREF(dollar_zonlnrlbk));
+			if (cdb_sc_onln_rlbk2 == failure)
+				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK);
+			/* else if (cdb_sc_onln_rlbk1 == status) we don't need to do anything other than trying again. Since this
+			 * is ^#t global, we don't need to GVCST_ROOT_SEARCH before continuing with the next restart because the
+			 * trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
+			 * actual trigger load
+			 */
+			/* We expect the above function to return with either op_tcommit or a tp_restart invoked.
+			 * In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
+			 * In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
+			 * Additionally we also want to avoid an infinite loop so limit the loop to what is considered
+			 * a huge iteration count and assertpro if that is reached as it suggests an out-of-design situation.
+			 */
+			assertpro(TPWRAP_HELPER_MAX_ATTEMPTS >= loopcnt);
+		}
+	} else
+	{
+		select_status = trigger_select(select_list, select_list_len);
+		assert(0 < dollar_tlevel);
+	}
+	TREF(ztrig_use_io_curr_device) = FALSE;
+	if (0 != file_name_len)
+	{
+		op_val.mvtype = op_pars.mvtype = MV_STR;
+		op_val.str.addr = (char *)file_name;;
+		op_val.str.len = file_name_len;
+		op_pars.str.len = SIZEOF(no_param);
+		op_pars.str.addr = (char *)&no_param;
+		op_close(&op_val, &op_pars);
+		/* Return back to the current device */
+		io_curr_device = save_io_curr_device;
+	}
+	return (TRIG_FAILURE == select_status);
+}
+
+STATICFNDEF boolean_t trigger_select_tpwrap_helper(char *select_list, uint4 select_list_len)
+{
+	enum cdb_sc		cdb_status;
+	boolean_t		select_status;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE);
+	select_status = trigger_select(select_list, select_list_len);
+	if (TRIG_SUCCESS == select_status)
+	{
+		GVTR_OP_TCOMMIT(cdb_status);
+		if (cdb_sc_normal != cdb_status)
+			t_retry(cdb_status);	/* won't return */
+	} else
+	{	/* Record cannot be committed - undo everything */
+		assert(donot_INVOKE_MUMTSTART);
+		DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);
+		/* Print $ztrigger/mupip-trigger output before rolling back TP */
+		TP_ZTRIGBUFF_PRINT;
+		OP_TROLLBACK(-1);		/* returns but kills implicit transaction */
+	}
+	REVERT;
+	return select_status;
+}
+
+STATICFNDEF boolean_t trigger_select(char *select_list, uint4 select_list_len)
+{
+	boolean_t		dump_all;
+	char			save_select_list[MAX_BUFF_SIZE];
+	char			*sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2;
+	int			gbl_len, prev_len;
+	mname_entry		gvname;
+	int			len, len1, badpos;
+	boolean_t		trig_name;
+	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+	gd_region		*save_gv_cur_region;
+	gv_namehead		*save_gv_target;
+	sgm_info		*save_sgm_info_ptr;
+	boolean_t		select_status;
+	gvnh_reg_t		*gvnh_reg;
+	gd_binding		*map, *start_map, *end_map;
+	gd_region		*reg, *reg_start, *reg_top;
+	int			*reg_done, reg_array_size, reg_index;
+	sgmnt_addrs		*csa;
+
+	assert(dollar_tlevel);
+	select_status = TRIG_SUCCESS;
+	memcpy(save_select_list, select_list, select_list_len);
+	save_select_list[select_list_len] = '\0';
+	dump_all = FALSE;
+	prev_len = 0;
 	if (0 == select_list_len)
 		dump_all = TRUE;
 	else
 	{
 		for (ptr1 = save_select_list, len = select_list_len;
-		     (NULL != (ptr2 = strchr(ptr1, '*'))) && (len > (len1 = INTCAST(ptr2 - ptr1)));
-		     ptr1 = ptr2 + 1)
+			(NULL != (ptr2 = strchr(ptr1, '*'))) && (len > (len1 = INTCAST(ptr2 - ptr1)));
+				ptr1 = ptr2 + 1)
 		{	/* look for either a real "dump-it-all" *, an error *, or a wildcard * */
 			/* A "*" anywhere in the select list (at a place where a global name would be) is the same as only a "*" */
 			len -= (len1 + 1);		/* Length after the "*" -- len1 is length before the "*" */
@@ -627,9 +745,8 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
 				break;
 		}
 	}
-	select_status = TRIG_SUCCESS;
 	if (dump_all)
-		dump_all_triggers(file_name_len, &op_val);
+		dump_all_triggers();
 	else
 	{
 		len = select_list_len;
@@ -652,55 +769,88 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
 						select_status, badpos);
 					continue;
 				}
-				SAVE_TRIGGER_REGION_INFO(save_currkey);
 				gbl_len = NAM_LEN(sel_ptr + 1, (int)(ptr1 - sel_ptr) - 1);
 				ptr1 = sel_ptr + 1;
-				if ((prev_len != gbl_len) || (0 != memcmp(prev_ptr, ptr1, gbl_len)))
-				{
-					prev_ptr = ptr1;
-					prev_len = gbl_len;
-					gvname.var_name.addr = ptr1;
-					gvname.var_name.len = gbl_len;
+				/* Skip only if the previous global is the same as the current */
+				if ((prev_len == gbl_len) && (0 == memcmp(prev_ptr, ptr1, gbl_len)))
+					continue;
+				SAVE_TRIGGER_REGION_INFO(save_currkey);
+				prev_ptr = ptr1;
+				prev_len = gbl_len;
+				start_map = gv_srch_map(gd_header, ptr1, gbl_len);
+				ptr1[gbl_len - 1]++;
+				end_map = gv_srch_map(gd_header, ptr1, gbl_len);
+				ptr1[gbl_len - 1]--;
+				gvname.var_name.addr = ptr1;
+				gvname.var_name.len = gbl_len;
+				if (start_map != end_map)
+				{	/* Global specification involves multiple regions */
+					reg_start = &gd_header->regions[0];
+					reg_array_size = gd_header->n_regions;
+					reg_done = malloc(reg_array_size * SIZEOF(*reg_done));
+					memset(reg_done, 0, reg_array_size * SIZEOF(*reg_done));
+					if ('*' == ptr1[gbl_len])
+						gvname.var_name.len++;
+					for (map = start_map; map <= end_map; map++)
+					{
+						reg = map->reg.addr;
+						GET_REG_INDEX(gd_header, reg_start, reg, reg_index);	/* sets "reg_index" */
+						assert(reg_array_size > reg_index);
+						if (!reg_done[reg_index])
+						{	/* this region first encountered now */
+							GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+							if (NULL == cs_addrs)	/* not BG or MM access method */
+								continue;
+							/* gv_target now points to ^#t in region "reg" */
+							if (0 != gv_target->root)
+								write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len,
+												trig_name);
+							reg_done[reg_index] = TRUE;
+						}
+					}
+					free(reg_done);
+				} else
+				{	/* Global specification involves only one region */
 					COMPUTE_HASH_MNAME(&gvname);
 					GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
-					if ('*' == *(ptr1 + gbl_len))
-						gvname.var_name.len++;
+					/* skip selecting/dumping triggers if not BG or MM access method */
+					if (NULL != cs_addrs)
+					{
+						if ('*' == ptr1[gbl_len])
+							gvname.var_name.len++;
+						SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
+						INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+						if (0 != gv_target->root)
+							write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len,
+											trig_name);
+					}
 				}
-				SET_GVTARGET_TO_HASHT_GBL(gv_target->gd_csa);
 			} else
 			{
 				if (len1 != (badpos = validate_input_trigger_name(ptr1, len1, NULL))) /* assignment is intended */
 				{ /* is the input name valid */
-					INVALID_NAME_ERROR("Invalid name entry in SELECT list: ",
-							   sel_ptr, select_status, badpos);
+					INVALID_NAME_ERROR("Invalid name entry in SELECT list: ", sel_ptr, select_status, badpos);
 					continue;
 				}
 				if (TRIGNAME_SEQ_DELIM == *(sel_ptr + (len1 - 1)))
-					/* drop the trailing # sign */
-					len1--;
+					len1--;	/* drop the trailing # sign */
 				gvname.var_name.addr = sel_ptr;
 				gvname.var_name.len = len1;
 				SAVE_TRIGGER_REGION_INFO(save_currkey);
-				SWITCH_TO_DEFAULT_REGION;
+				for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+				{
+					GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+					if (NULL == cs_addrs)	/* not BG or MM access method */
+						continue;
+					/* gv_target now points to ^#t in region "reg" */
+					if (0 == gv_target->root)
+						continue;
+					write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len, trig_name);
+				}
 			}
-			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-			if (0 != gv_target->root)
-				write_gbls_or_names(gvname.var_name.addr, gvname.var_name.len, file_name_len, &op_val, trig_name);
 			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 		} while (NULL != (sel_ptr = strtok_r(NULL, ",", &strtok_ptr)));	/* Embedded assignment is intended */
 	}
-	if (0 != file_name_len)
-	{
-		op_val.mvtype = op_pars.mvtype = MV_STR;
-		op_val.str.addr = (char *)file_name;;
-		op_val.str.len = file_name_len;
-		op_pars.str.len = SIZEOF(no_param);
-		op_pars.str.addr = (char *)&no_param;
-		op_close(&op_val, &op_pars);
-		/* Return back to the current device */
-		io_curr_device = save_io_curr_device;
-	}
 	return select_status;
 }
-
 #endif
diff --git a/sr_unix/trigger_select_protos.h b/sr_unix/trigger_select_protos.h
index 7660921..ed32c44 100644
--- a/sr_unix/trigger_select_protos.h
+++ b/sr_unix/trigger_select_protos.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -13,10 +13,12 @@
 #define TRIGGER_SELECT_PROTOS_INCLUDED
 
 STATICFNDCL void write_subscripts(char *out_rec, char **out_ptr, char **sub_ptr, int *sub_len);
-STATICFNDCL void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, int nam_indx);
-STATICFNDCL void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, uint4 file_name_len, mval *op_val, boolean_t trig_name);
-STATICFNDCL void dump_all_triggers(uint4 file_name_len, mval *op_val);
+STATICFNDCL void write_out_trigger(char *gbl_name, uint4 gbl_name_len, int nam_indx);
+STATICFNDCL void write_gbls_or_names(char *gbl_name, uint4 gbl_name_len, boolean_t trig_name);
+STATICFNDCL void dump_all_triggers(void);
 
-boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len);
+boolean_t trigger_select_tpwrap(char *select_list, uint4 select_list_len, char *file_name, uint4 file_name_len);
+STATICFNDCL boolean_t trigger_select_tpwrap_helper(char *select_list, uint4 select_list_len);
+STATICFNDCL boolean_t trigger_select(char *select_list, uint4 select_list_len);
 
 #endif /* TRIGGER_SELECT_PROTOS_INCLUDED */
diff --git a/sr_unix/trigger_source_read_andor_verify.c b/sr_unix/trigger_source_read_andor_verify.c
index 5afcf20..07f4f94 100644
--- a/sr_unix/trigger_source_read_andor_verify.c
+++ b/sr_unix/trigger_source_read_andor_verify.c
@@ -23,12 +23,11 @@
 #include "trigger.h"
 #include "trigger_fill_xecute_buffer.h"
 #include "trigger_gbl_fill_xecute_buffer.h"
-#include "trigger_read_name_entry.h"
 #include "trigger_source_read_andor_verify.h"
 #include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
 #include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
 #include "hashtab.h"			/* for STR_HASH (in COMPUTE_HASH_MNAME) */
-#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL */
 #include "filestruct.h"			/* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
 #include "mvalconv.h"
 #include "gdscc.h"			/* needed for tp.h */
@@ -49,6 +48,11 @@
 #include "mv_stent.h"
 #include "gv_trigger_protos.h"
 #include "hashtab_mname.h"
+#include "hashtab_str.h"		/* needed by trigger_update_protos.h */
+#include "trigger_update_protos.h"	/* for trigger_name_search prototype */
+#include "change_reg.h"			/* for "change_reg" prototype */
+#include "gvnh_spanreg.h"
+#include "min_max.h"
 
 GBLREF	uint4			dollar_tlevel;
 GBLREF	sgmnt_addrs		*cs_addrs;
@@ -64,19 +68,32 @@ GBLREF	int4			gtm_trigger_depth;
 GBLREF	trans_num		local_tn;
 GBLREF	unsigned int		t_tries;
 GBLREF	unsigned char		t_fail_hist[CDB_MAX_TRIES];
+GBLREF	rtn_tabent		*rtn_names_end;
 #ifdef DEBUG
 GBLREF	boolean_t		donot_INVOKE_MUMTSTART;
 #endif
 
 LITREF	mval			literal_batch;
-LITREF	mval			literal_hasht;
 
 #define TRIG_FAILURE_RC	-1
 
+#define	ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(TRIGNAME)								\
+{														\
+	DCL_THREADGBL_ACCESS;											\
+														\
+	SETUP_THREADGBL_ACCESS;											\
+	if (!TREF(op_fntext_tlevel))										\
+	{													\
+		CLEAR_IMPLICIT_TP_BEFORE_ERROR;									\
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, TRIGNAME->len, TRIGNAME->addr);	\
+	}													\
+}
+
+STATICFNDCL gd_region *find_region(mstr *regname);
 STATICFNDCL CONDITION_HANDLER(trigger_source_raov_ch);
-STATICFNDCL int trigger_source_raov(mstr *trigname, trigger_action trigger_op);
-STATICFNDCL int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op);
-STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc);
+STATICFNDCL int trigger_source_raov(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec);
+STATICFNDCL int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec);
+STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc, gd_region *reg);
 
 error_def(ERR_DBROLLEDBACK);
 error_def(ERR_TPRETRY);
@@ -90,13 +107,13 @@ error_def(ERR_TRIGNAMENF);
  * condition caused the error, this will restart and retry the transaction. Note that since skip_INVOKE_RESTART
  * is not set before this op_tcommit, it with throw a restart rather than returning a restartable code.
  */
-#define CLEAR_IMPLICIT_TP_BEFORE_ERROR						\
-	if (tp_pointer->implicit_trigger && (0 == gtm_trigger_depth))		\
-	{	/* We have an implicit TP fence */				\
-		enum cdb_sc		status;					\
-		/* Eliminate transaction by commiting it (nothing was done) */	\
-		status = op_tcommit();						\
-		assert(cdb_sc_normal == status);				\
+#define CLEAR_IMPLICIT_TP_BEFORE_ERROR							\
+	if (dollar_tlevel && tp_pointer->implicit_trigger && (0 == gtm_trigger_depth))	\
+	{	/* We have an implicit TP fence */					\
+		enum cdb_sc		status;						\
+		/* Eliminate transaction by commiting it (nothing was done) */		\
+		status = op_tcommit();							\
+		assert(cdb_sc_normal == status);					\
 	}
 
 
@@ -120,6 +137,24 @@ CONDITION_HANDLER(trigger_source_raov_ch)
 	NEXTCH;
 }
 
+STATICFNDEF gd_region *find_region(mstr *regname)
+{
+	gd_region	*reg, *reg_top;
+	mstr		tmpstr;
+	int		comp;
+
+	assert(NULL != gd_header);
+	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
+	{
+		tmpstr.len = reg->rname_len;
+		tmpstr.addr = (char *)reg->rname;
+		MSTR_CMP(tmpstr, *regname, comp);
+		if (0 == comp)
+			return reg;
+	}
+	return NULL;
+}
+
 /* Routine to check on the named trigger. This routine is called from (at least) two places: the above get_src_line()
  * routine where it is called to retrieve trigger source (left in source definition buffer of the trigger) and the other
  * time it is called from op_setzbrk() to load and/or compile the trigger. In both cases, the trigger may be loaded or
@@ -130,48 +165,88 @@ CONDITION_HANDLER(trigger_source_raov_ch)
  * The following sitations can exist:
  *
  *   1. No trigger by the given name is loaded. For this situation, we need to locate and load the trigger and its source.
- *   2. Trigger is loaded but no source is in the trigger source buffer. For this situation, verify the trigger load is
- *      current. If not, restart things. If is current, load the source.
- *   3. Trigger and source both loaded. Verify the trigger is current. if not restart things.
+ *   2. Trigger is loaded but no source is in the trigger source buffer. For this situation, load the source and mark the
+ *      trigger as part of the transaction.
+ *   3. Trigger and source both loaded. For this situation, mark the trigger as part of the transaction.
  *
- * In addition, we can be entered either with a TP FENCE already enabled or without one. How we deal with restarts varries
- * depending on which is true:
+ * If a TP fence is not in place, we provide an implcit wrapper that will catch our restarts and reinvoke the logic
+ *	that will reload the trigger from scratch. We do not verify that the trigger information in memory is fresh.
  *
- *   - If in a TP fence already, if we hit a condition where we need to restart, we throw a trigger based restart condition
- *     but because we aren't necessarily driving any triggers here, there is nothing in the restart process that actually
- *     forces the trigger to reload before we come back here. So we call gvtr_free() on the region in question to force
- *     those triggers to reload completely, even if it is us that ends up doing it when we get back here.
- *   - If NOT under a TP fence already, we provide an implcit wrapper that will catch our restarts and reinvoke the logic
- *     that will reload the trigger from scratch.
+ * If a TP FENCE is in place and we are in the final retry, we verify that the triggers are current and reload them if
+ *      not. This avoids the possibility of using stale triggers.
  *
  * Note, this routine is for loading trigger source when we are not driving triggers. The trigger_fill_xecute_buffer()
  * should be used when fetching source for trigger execution because it is lighter weight with built-in trigger refetch
  * logic since we are using the globals the triggers live in. In this case, the trigger access is adhoc for the $TEXT()
  * ZPRINT and ZBREAK uses.
  */
-int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
+int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op, rhdtyp **rtn_vec)
 {
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
+	char			*ptr, *ptr_beg, *ptr_top;
+	enum cdb_sc		failure;
+	gd_region		*reg;
 	int			src_fetch_status;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+	mstr			regname;
+	rtn_tabent		*rttabent;
 	uint4			cycle;
 	DEBUG_ONLY(unsigned int	lcl_t_tries;)
-	enum cdb_sc		failure;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	assert(NULL != trigname);
 	assert((NULL != trigname->addr) && (0 != trigname->len));
-	/* Before we try to save anything, see if there is something to save and initialize stuff if not */
 	if (NULL == gd_header)
-	{	/* If we do initialize things, start off in the default region since we need it shortly anyway */
 		gvinit();
-		SWITCH_TO_DEFAULT_REGION;
+	DBGTRIGR((stderr, "trigger_source_read_andor_verify: Entered with trigger action %d $tlevel=%d, $trigdepth=%d\n",
+				trigger_op, dollar_tlevel, gtm_trigger_depth));
+	/*
+	 * Input parameter "trigname" is of the form
+	 *	a) <21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME] OR
+	 *	b) <28-BYTE-USER-SPECIFIED-TRIGNAME>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME]
+	 * where
+	 *	<21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT> OR <28-BYTE-USER-SPECIFIED-TRIGNAME> is the
+	 *		auto-generated or user-specified trigger name we are searching for
+	 *	RUNTIME-DISAMBIGUATOR is the unique string appended at the end by the runtime to distinguish
+	 *		multiple triggers in different regions with the same auto-generated or user-given name
+	 *	REGION-NAME is the name of the region in the gld where we specifically want to search for trigger names
+	 *	[] implies optional parts
+	 *
+	 * Example usages are
+	 *	  x#         : trigger routine user-named "x"
+	 *	  x#1#       : trigger routine auto-named "x#1"
+	 *	  x#1#A      : trigger routine auto-named "x#1" but also runtime disambiguated by "#A" at the end
+	 *	  x#/BREG    : trigger routine user-named "x" in region BREG
+	 *	  x#A/BREG   : trigger routine user-named "x", runtime disambiguated by "#A", AND in region BREG
+	 *	  x#1#/BREG  : trigger routine auto-named "x#1" in region BREG
+	 *	  x#1#A/BREG : trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
+	 */
+	/* First lets locate the trigger. Try simple way first - lookup in routine name table.
+	 * But "find_rtn_tabent" function has no clue about REGION-NAME so remove /REGION-NAME (if any) before invoking it.
+	 */
+	regname.len = 0;
+	reg = NULL;
+	for (ptr_beg = trigname->addr, ptr_top = ptr_beg + trigname->len, ptr = ptr_top - 1; ptr >= ptr_beg; ptr--)
+	{
+		/* If we see a '#' and have not yet seen a '/' we are sure no region-name disambiguator has been specified */
+		if ('#' == *ptr)
+			break;
+		if ('/' == *ptr)
+		{
+			trigname->len = ptr - trigname->addr;
+			ptr++;
+			regname.addr = ptr;
+			regname.len = ptr_top - ptr;
+			reg = find_region(&regname);	/* find region "regname" in "gd_header" */
+			if (NULL == reg)
+			{	/* Specified region-name is not present in current gbldir.
+	 			 * Treat non-existent region name as if trigger was not found.
+				 */
+				ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+				return TRIG_FAILURE_RC;
+			}
+			break;
+		}
 	}
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	DBGTRIGR((stderr, "trigger_source_raov: Entered with trigger action %d\n", trigger_op));
 	/* First determination is if a TP fence is already in operation or not */
 	if (0 == dollar_tlevel)
 	{	/* We need a TP fence - provide one */
@@ -185,7 +260,7 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
 		for (;;)
 		{	/* Now that we are TP wrapped, fetch the trigger source lines from the ^#t global */
 			DEBUG_ONLY(lcl_t_tries = t_tries);
-			src_fetch_status = trigger_source_raov_tpwrap_helper(trigname, trigger_op);
+			src_fetch_status = trigger_source_raov_tpwrap_helper(trigname, trigger_op, reg, rtn_vec);
 			if ((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status))
 			{
 				assert(0 == dollar_tlevel); /* op_tcommit should have made sure of this */
@@ -213,14 +288,15 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
 		}
 	} else
 		/* no return if TP restart */
-		src_fetch_status = trigger_source_raov(trigname, trigger_op);
+		src_fetch_status = trigger_source_raov(trigname, trigger_op, reg, rtn_vec);
 	assert((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status));
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
+	DBGTRIGR((stderr, "trigger_source_read_andor_verify: leaving with source from 0x%lx\n",
+				(*rtn_vec)?(*((rhdtyp **)rtn_vec))->trigr_handle:NULL));
 	return src_fetch_status;
 }
 
 /* Now TP wrap and fetch the trigger source lines from the ^#t global */
-STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op)
+STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec)
 {
 	enum cdb_sc	cdb_status;
 	int		rc;
@@ -228,7 +304,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
 	DBGTRIGR((stderr, "trigger_source_tpwrap_helper: Entered\n"));
 	ESTABLISH_RET(trigger_source_raov_ch, SIGNAL);
 	assert(donot_INVOKE_MUMTSTART);
-	rc = trigger_source_raov(trigname, trigger_op);
+	rc = trigger_source_raov(trigname, trigger_op, reg, rtn_vec);
 	assert((0 == rc) || (TRIG_FAILURE_RC == rc));
 	/* Finish it now verifying it completed successfully */
 	GVTR_OP_TCOMMIT(cdb_status);
@@ -245,30 +321,104 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
  * loading the trigger, loading the source, verifying proper source/trigger is loaded and compiling if
  * desired. If we complete successfully, returns 0. Error returns caught by condition handlers can return other values.
  */
-STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
+STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op, gd_region *reg, rhdtyp **rtn_vec)
 {
-	sgmnt_addrs		*csa=NULL;
-	sgmnt_data_ptr_t	csd;
-	rhdtyp			*rtn_vector;
+	boolean_t		runtime_disambiguator_specified;
+	gd_region		*save_gv_cur_region;
+	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
 	gv_namehead		*gvt;
+	gv_namehead		*save_gv_target;
+	gvnh_reg_t		*gvnh_reg;
+	gv_trigger_t		*trigdsc;
 	gvt_trigger_t		*gvt_trigger;
-	mstr			gbl, xecute_buff;
 	int			index;
-	mval			trig_index;
-	gv_trigger_t		*trigdsc;
-	uint4			cycle_start;
-	boolean_t		triggers_reloaded, db_trigger_cycle_mismatch, ztrig_cycle_mismatch;
+	mident			rtn_name;
+	mstr			gbl, xecute_buff;
+	mval			trig_index, val;
+	rhdtyp			*rtn_vector;
+	rtn_tabent		*rttabent;
+	sgm_info		*save_sgm_info_ptr;
+	sgmnt_addrs		*csa, *regcsa;
+	sgmnt_data_ptr_t	csd;
+	boolean_t		db_trigger_cycle_mismatch, ztrig_cycle_mismatch, needs_reload, needs_restart;
+	DCL_THREADGBL_ACCESS;
 
+	SETUP_THREADGBL_ACCESS;
 	assert(dollar_tlevel);		/* A TP wrap should have been done by the caller if needed */
-	/* First lets locate the trigger. Try simple way first - lookup in routine name table */
-	if (NULL == (rtn_vector = find_rtn_hdr(trigname)))	/* Note assignment */
-	{	/* Wasn't found - look for it the harder way in the #t of the default region */
-		if(TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+	DBGTRIGR((stderr, "trigger_source_raov: Entered with trigger action %d\n", trigger_op));
+	/* Before we try to save anything, see if there is something to save and initialize stuff if not */
+	SAVE_TRIGGER_REGION_INFO(save_currkey);
+	if (find_rtn_tabent(&rttabent, trigname))
+		rtn_vector = rttabent->rt_adr;
+	else
+		rtn_vector = NULL;
+	DBGTRIGR((stderr, "trigger_source_raov: routine was %sfound\n", (NULL == rtn_vector)?"not ":""));
+	/* If region is specified, a null-runtime-disambiguator is treated as if runtime-disambiguator was not specified.
+	 * If region is NOT specified, a null-runtime-disambiguator is treated as if runtime-disambiguator was specified.
+	 */
+	runtime_disambiguator_specified = ('#' != trigname->addr[trigname->len - 1]);
+	if (!runtime_disambiguator_specified && (NULL != reg))
+	{	/* Region-name has been specified and no runtime-disambiguator specified. Need to further refine the
+		 * search done by find_rtn_tabent to focus on the desired region in case multiple routines with the same
+		 * trigger name (but different runtime-disambiguators) exist.
+		 */
+		rtn_name.len = MIN(trigname->len, MAX_MIDENT_LEN);
+		rtn_name.addr = trigname->addr;
+		if (!reg->open)
+			gv_init_reg(reg);	/* Open the region before obtaining "csa" */
+		regcsa = &FILE_INFO(reg)->s_addrs;
+		assert('#' == rtn_name.addr[rtn_name.len - 1]);
+		for ( ; rttabent <= rtn_names_end; rttabent++)
+		{
+			if ((rttabent->rt_name.len < rtn_name.len) || memcmp(rttabent->rt_name.addr, rtn_name.addr, rtn_name.len))
+			{	/* Past the list of routines with same name as trigger but different runtime disambiguators */
+				rtn_vector = NULL;
+				break;
+			}
+			rtn_vector = rttabent->rt_adr;
+			trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
+			gvt_trigger = trigdsc->gvt_trigger;
+			gvt = gvt_trigger->gv_target;
+			/* Target region and trigger routine's region do not match, continue */
+			if (gvt->gd_csa != regcsa)
+				continue;
+			/* Check if global name associated with the trigger is indeed mapped to the corresponding region
+			 * by the gld.  If not treat this case as if the trigger is invisible and move on
+			 */
+			gbl.addr = gvt->gvname.var_name.addr;
+			gbl.len = gvt->gvname.var_name.len;
+			TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
+			csa = cs_addrs;
+			csd = csa->hdr;
+			COMPUTE_HASH_MNAME(&gvt->gvname);
+			GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg);	/* does tp_set_sgm() */
+			if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+					|| ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+				continue;
+			/* Target region and trigger routine's region match, break (this check is a formality) */
+			if (gvt->gd_csa == regcsa)
+				break;
+		}
+	}
+	csa = NULL;
+	if (NULL == rtn_vector)
+	{	/* If runtime disambiguator was specified and routine is not found, look no further.
+		 * Otherwise, look for it in the #t global of any (or specified) region in current gbldir.
+		 */
+		DBGTRIGR((stderr, "trigger_source_raov: find trigger by name without disambiguator\n"));
+		if (runtime_disambiguator_specified
+			|| (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc, reg)))
+		{
+			RESTORE_TRIGGER_REGION_INFO(save_currkey);
+			ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
 			return TRIG_FAILURE_RC;
+		}
+		rtn_vector = trigdsc->rtn_desc.rt_adr;
 	} else
 	{	/* Have a routine header addr. From that we can get the gv_trigger_t descriptor and from that, the
-		 * gvt_trigger and other necessaries
+		 * gvt_trigger and other necessities.
 		 */
+		DBGTRIGR((stderr, "trigger_source_raov: routine header found, now load it\n"));
 		trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
 		gvt_trigger = trigdsc->gvt_trigger;			/* We now know our base block now */
 		index = trigdsc - gvt_trigger->gv_trig_array + 1;	/* We now know our trigger index value */
@@ -278,122 +428,116 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
 		TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
 		csa = cs_addrs;
 		csd = csa->hdr;
-		assert(csd == cs_data);
-		/* Verify trigger is current. Note we use CSA for this check since within this transaction we could have multiple
-		 * triggers from the same global in flight preventing us from reloading a trigger. By checking CSA, we at least get
-		 * a consistent trigger view and depend on CSA being checked as current in op_tcommit.
-		 */
-		triggers_reloaded = FALSE;
-		SHM_READ_MEMORY_BARRIER;
-		tp_set_sgm();
-		db_trigger_cycle_mismatch = (csa->db_trigger_cycle != gvt->db_trigger_cycle);
-		ztrig_cycle_mismatch = (csa->db_dztrigger_cycle && (gvt->db_dztrigger_cycle != csa->db_dztrigger_cycle));
-		if (db_trigger_cycle_mismatch || ztrig_cycle_mismatch)
-		{       /* The process' view of the triggers is stale. We cannot proceed unless the triggers get reloaded.
-			 * If triggers have been driven for this global in this transaction, we have to throw a restart. To
-			 * reload and go if triggers have already been driven creates a potential consistency issues plus
-			 * the possibility that we could remove a trigger actively running which will cause major issues
-			 * when the trigger returns.
-			 *
-			 * To prevent these sort of issues, we compare the local_tn value when the last trigger was driven
-			 * in this global (recorded by gtm_trigger() in gvt->trig_local_tn) to the current local_tn value.
-			 * If the same, we have to restart. Else, we can reload the triggers and keep going.
-			 *
-			 * Triggers can be invoked only by GT.M and Update process. Out of these, we expect only
-			 * GT.M to see restarts due to concurrent trigger changes. Update process is the only
-			 * updater on the secondary so we dont expect it to see any concurrent trigger changes
-			 * Assert accordingly. Note similar asserts occur in t_end.c and tp_tend.c.
+		if (runtime_disambiguator_specified && (NULL != reg))
+		{	/* Runtime-disambiguator has been specified and routine was found. But region-name-disambiguator
+			 * has also been specified. Check if found routine is indeed in the specified region. If not
+			 * treat it as a failure to find the trigger.
 			 */
-			DBGTRIGR((stderr, "trigger_source_raov: Trigger cycle difference detected - db_trigger_cycle - "
-				  "csa: %d, csd: %d, gvt: %d  db_ztrigger_cycle: csa: %d, gvt: %d\n",
-				  csa->db_trigger_cycle, csd->db_trigger_cycle, gvt->db_trigger_cycle,
-				  csa->db_dztrigger_cycle, gvt->db_dztrigger_cycle));
-			assert(IS_GTM_IMAGE);
-			if ((local_tn == gvt->trig_local_tn) && db_trigger_cycle_mismatch)
-			{	/* Already dispatched trigger for this gvn in this transaction - must restart. But do so ONLY
-				 * if the process' trigger view changed because of a concurrent trigger load/unload and NOT
-				 * because of $ZTRIGGER as part of this transaction as that could cause unintended restarts.
-				 */
-				assert(CDB_STAGNATE > t_tries);
-				DBGTRIGR((stderr, "trigger_source_raov: throwing TP restart\n"));
-				t_retry(cdb_sc_triggermod);
-			}
-			cycle_start = csa->db_trigger_cycle;
-			gvtr_db_read_hasht(csa);
-			gvt_trigger = gvt->gvt_trigger;
-			if (NULL == gvt_trigger)
-			{	/* No triggers were loaded for this region (all gone now) */
-				CLEAR_IMPLICIT_TP_BEFORE_ERROR;
-				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+			if (!reg->open)
+				gv_init_reg(reg);
+			if (&FILE_INFO(reg)->s_addrs != csa)
+			{
+				RESTORE_TRIGGER_REGION_INFO(save_currkey);
+				ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+				return TRIG_FAILURE_RC;
 			}
-			gvt->db_trigger_cycle = cycle_start;
-			gvt->db_dztrigger_cycle = csa->db_dztrigger_cycle;
-			DBGTRIGR((stderr, "trigger_source_raov: triggers reloaded - "
-				  "gvt->db_trigger_cycle updated to %d\n", gvt->db_trigger_cycle));
-			if (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+			/* Check if global name is indeed mapped to this region by the gld.  If not treat this case as
+			 * if the trigger is invisible and issue an error
+			 */
+			COMPUTE_HASH_MNAME(&gvt->gvname);
+			GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg);	/* does tp_set_sgm() */
+			if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+					|| ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+			{
+				RESTORE_TRIGGER_REGION_INFO(save_currkey);
+				ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
 				return TRIG_FAILURE_RC;
-			triggers_reloaded = TRUE;
-		} else
-			DBGTRIGR((stderr, "trigger_source_raov: trigger validated\n"));
-		/* Only proceed with this next section at this point if triggers have not been reloaded. If they have
-		 * been reloaded, the rtn_vector address will have changed causing issues in this section. In that case,
-		 * we just need to fall out of this section to the common section which rebuilds things as necessary.
-		 */
-		if (!triggers_reloaded)
-		{	/* Triggers were not reloaded - see if we need to load the source or not */
-			if (TRIGGER_COMPILE == trigger_op)
-			{	/* This trigger has been verified so if it is already compiled, we are done */
-				if (NULL != trigdsc->rtn_desc.rt_adr)
-					return 0;
 			}
-			/* Else we need the trigger source loaded */
-			if (0 == ((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len)
+		}
+		DBGTRIGR((stderr, "trigger_source_raov: existing trigger routine has %d bytes of source\n",
+					((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len));
+		assert(csd == cs_data);
+		tp_set_sgm();
+		/* If we are in the final retry, ensure we dont rely on stale triggers as we cannot afford any restarts now */
+		if (CDB_STAGNATE <= t_tries)
+		{
+			ztrig_cycle_mismatch = (csa->db_dztrigger_cycle && (gvt->db_dztrigger_cycle != csa->db_dztrigger_cycle));
+			db_trigger_cycle_mismatch = (csa->db_trigger_cycle != gvt->db_trigger_cycle);
+			needs_reload = (db_trigger_cycle_mismatch || ztrig_cycle_mismatch);
+			DBGTRIGR((stderr, "trigger_source_raov: ztrig_cycle_mismatch=%d\tdb_trigger_cycle_mismatch=%d\treload?%d\n",
+				ztrig_cycle_mismatch, db_trigger_cycle_mismatch, needs_reload));
+			if (needs_reload && (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc, reg)))
 			{
-				SET_GVTARGET_TO_HASHT_GBL(csa);
-				INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-				assert(0 == trigdsc->xecute_str.str.len);	/* Make sure not replacing/losing a buffer */
-				i2mval(&trig_index, index);
-				xecute_buff.addr = trigger_gbl_fill_xecute_buffer(gbl.addr, gbl.len, &trig_index, NULL,
-										  (int4 *)&xecute_buff.len);
-				trigdsc->xecute_str.str = xecute_buff;
+				RESTORE_TRIGGER_REGION_INFO(save_currkey);
+				ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
+				return TRIG_FAILURE_RC;
 			}
 		}
-		/* We have referenced this trigger's source. Mark it in gv_target so we know if we have to restart later
-		 * if trigger changes instead of just reloading it on-the-fly.
+		/* Now that this TP has relied on this process' current trigger view, ensure that any later action in the same
+		 * TP that detects and reloads newer triggers (e.g. trigger invocation) restarts the entire TP transaction.
 		 */
 		gvt->trig_local_tn = local_tn;
+
+		/* If this trigger is already compiled, we are done */
+		if ((TRIGGER_COMPILE == trigger_op) && (NULL != trigdsc->rtn_desc.rt_adr))
+		{
+			DBGTRIGR((stderr, "trigger_source_raov: trigger already compiled, all done\n"));
+			RESTORE_TRIGGER_REGION_INFO(save_currkey);
+			*rtn_vec = rtn_vector;
+			return 0;
+		}
+		/* Else load the trigger source as needed */
+		if (0 == trigdsc->xecute_str.str.len)
+		{
+			DBGTRIGR((stderr, "trigger_source_raov: get the source\n"));
+			SET_GVTARGET_TO_HASHT_GBL(csa);
+			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+			assert(0 == trigdsc->xecute_str.str.len);	/* Make sure not replacing/losing a buffer */
+			i2mval(&trig_index, index);
+			xecute_buff.addr = trigger_gbl_fill_xecute_buffer(gbl.addr, gbl.len, &trig_index, NULL,
+									  (int4 *)&xecute_buff.len);
+			trigdsc->xecute_str.str = xecute_buff;
+		}
 	}
 	/* If the trigger is not already compiled, it needs to be since the routine header is the method for obtaining the
 	 * trigger descriptor. If routine is already compiled, we don't need to compile it again.
 	 */
 	if ((TRIGGER_COMPILE == trigger_op) || (NULL == trigdsc->rtn_desc.rt_adr))
 	{
+		DBGTRIGR((stderr, "trigger_source_raov: compile it\n"));
 		if (0 != gtm_trigger_complink(trigdsc, TRUE))
 		{
 			PRN_ERROR;	/* Flush out any compiler messages for compile record */
 			rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGCOMPFAIL, 2,
-					trigdsc->rtn_desc.rt_name.len, trigdsc->rtn_desc.rt_name.addr);
+					trigdsc->rtn_desc.rt_name.len - 1, trigdsc->rtn_desc.rt_name.addr);
 		}
 		assert(trigdsc->rtn_desc.rt_adr);
 		assert(trigdsc->rtn_desc.rt_adr == CURRENT_RHEAD_ADR(trigdsc->rtn_desc.rt_adr));
 		/* If compile only, the source code is no longer needed so release it */
 		if ((TRIGGER_COMPILE == trigger_op) && (0 < trigdsc->xecute_str.str.len))
 		{
+			DBGTRIGR((stderr, "trigger_source_raov: free the source\n"));
 			free(trigdsc->xecute_str.str.addr);
 			trigdsc->xecute_str.str.addr = NULL;
 			trigdsc->xecute_str.str.len = 0;
 		}
+		rtn_vector = trigdsc->rtn_desc.rt_adr;
 	} else
 	{
 		assert(TRIGGER_SRC_LOAD == trigger_op);
 		assert(NULL != trigdsc->xecute_str.str.addr);
 		assert(0 < trigdsc->xecute_str.str.len);
 	}
+	RESTORE_TRIGGER_REGION_INFO(save_currkey);
+	assert(rtn_vector);
+	assert(trigdsc == rtn_vector->trigr_handle);
+	assert(((gv_trigger_t *)rtn_vector->trigr_handle)->xecute_str.str.len);
+	*rtn_vec = rtn_vector;
 	return 0;
 }
 
 /* Routine called when need triggers loaded for a given global */
-STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc)
+STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc, gd_region *reg)
 {
 	mval			val;
 	char			*ptr;
@@ -404,25 +548,21 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
 	gvt_trigger_t		*gvt_trigger;
 	mstr			xecute_buff;
 	mname_entry		gvname;
-	int			index;
+	int			index, n;
 	mval			trig_index;
 	gv_trigger_t		*trigdsc;
 	uint4			cycle_start;
 	gvnh_reg_t		*gvnh_reg;
-	DCL_THREADGBL_ACCESS;
+	boolean_t		name_not_found;
 
-	SETUP_THREADGBL_ACCESS;
-	/* Find region trigger name is in */
-	if (!trigger_read_name_entry(trigname, &val))
-	{	/* Trigger name not found - nothing we can do */
-		if (!TREF(op_fntext_tlevel))
-		{
-			CLEAR_IMPLICIT_TP_BEFORE_ERROR;
-			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
-		}
-		return TRIG_FAILURE;
-	}
+	assert(dollar_tlevel);
+	DBGTRIGR((stderr, "trigger_source_raov_trigload: entry for %s\n", trigname->addr));
+	/* Find region trigger name is in. If "region-name" has been specified, find only in that region. */
+	name_not_found = !trigger_name_search(trigname->addr, trigname->len, &val, &reg);
+	if (name_not_found)
+		return TRIG_FAILURE;	/* Trigger name not found - nothing we can do */
 	/* Extract region name and trigger index number from result */
+	assert(NULL != reg);
 	ptr = val.str.addr;
 	len = STRLEN(ptr);	/* Do it this way since "val" has multiple fields null separated */
 	ptr += len;
@@ -433,6 +573,14 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
 	gvname.var_name.len = len;
 	COMPUTE_HASH_MNAME(&gvname);
 	GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);	/* does tp_set_sgm() */
+	if (NULL != gvnh_reg->gvspan)
+	{
+		assert(gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)); /* "trigger_name_search" would have ensured this */
+		GV_BIND_SUBSREG(gd_header, reg, gvnh_reg);	/* sets gv_target/gv_cur_region/cs_addrs */
+	} else
+	{	/* gv_target/gv_cur_region/cs_addrs would have been set by GV_BIND_NAME_ONLY */
+		assert(gv_cur_region == reg);
+	}
 	gvt = gv_target;
 	assert(cs_addrs == gvt->gd_csa);
 	csa = gvt->gd_csa;
@@ -443,15 +591,15 @@ STATICFNDEF boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t
 	gvtr_db_read_hasht(csa);
 	gvt_trigger = gvt->gvt_trigger;
 	if (NULL == gvt_trigger)
-	{	/* No trigger were loaded for this region (all gone now) */
-		CLEAR_IMPLICIT_TP_BEFORE_ERROR;
-		rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+	{
+		if (CDB_STAGNATE > t_tries)
+			t_retry(cdb_sc_triggermod);
+		return TRIG_FAILURE; /* Return an error instead of TRIGDEFBAD */
 	}
 	gvt->db_trigger_cycle = cycle_start;
 	gvt->db_dztrigger_cycle = csa->db_dztrigger_cycle;
 	gvt->trig_local_tn = local_tn;		/* Mark this trigger as being referenced in this transaction */
-	DBGTRIGR((stderr, "trigger_source_raov_trigload: gvt->db_trigger_cycle updated to %d\n",
-		  gvt->db_trigger_cycle));
+	DBGTRIGR((stderr, "trigger_source_raov_trigload: gvt->db_trigger_cycle updated to %d\n", gvt->db_trigger_cycle));
 	SET_GVTARGET_TO_HASHT_GBL(csa);
 	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
 	trigdsc = &gvt_trigger->gv_trig_array[index - 1];
diff --git a/sr_unix/trigger_source_read_andor_verify.h b/sr_unix/trigger_source_read_andor_verify.h
index 0f43204..8f65544 100644
--- a/sr_unix/trigger_source_read_andor_verify.h
+++ b/sr_unix/trigger_source_read_andor_verify.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2011, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -18,7 +18,7 @@ typedef enum
 	TRIGGER_COMPILE
 } trigger_action;
 
-int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op);
+int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op, rhdtyp **rtn_vec);
 
 #endif /* GTM_TRIGGER */
 
diff --git a/sr_unix/trigger_subs_def.h b/sr_unix/trigger_subs_def.h
index e17b73b..d58db8e 100644
--- a/sr_unix/trigger_subs_def.h
+++ b/sr_unix/trigger_subs_def.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2011, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -11,16 +11,24 @@
 
 /* Define trigger subscript types/order. Used to define enum trig_subs_t in trigger.h
  * and trigger_subs in mtables.c.
+ *
+ * Note : The order of lines below matters to a great extent. For example TRIGNAME needs to be before CMD
+ * which in turn needs to be before XECUTE as that otherwise affects the output of MUPIP TRIGGER -SELECT.
+ * There are other requirements like this in MUPIP TRIGGER -SELECT output format.
+ * In addition, BHASH and LHASH need to be at the end of this list. The #define of NUM_SUBS relies on this.
  */
 
-TRIGGER_SUBDEF(TRIGNAME),
-TRIGGER_SUBDEF(GVSUBS),
-TRIGGER_SUBDEF(CMD),
-TRIGGER_SUBDEF(OPTIONS),
-TRIGGER_SUBDEF(DELIM),
-TRIGGER_SUBDEF(ZDELIM),
-TRIGGER_SUBDEF(PIECES),
-TRIGGER_SUBDEF(XECUTE),
-TRIGGER_SUBDEF(CHSET),
-TRIGGER_SUBDEF(LHASH),
-TRIGGER_SUBDEF(BHASH)
+/*
+TRIGGER_SUBSDEF (trigsubstype, subsname,   litmvalname,      trigfilequal, partofhash                       )
+*/
+TRIGGER_SUBSDEF (TRIGNAME_SUB, "TRIGNAME", literal_trigname, "-name=",     TRSBS_IN_NONE                    )
+TRIGGER_SUBSDEF (GVSUBS_SUB,   "GVSUBS",   literal_gvsubs,   "",           (TRSBS_IN_LHASH | TRSBS_IN_BHASH) )
+TRIGGER_SUBSDEF (CMD_SUB,      "CMD",      literal_cmd,      "-commands=", TRSBS_IN_NONE                    )
+TRIGGER_SUBSDEF (OPTIONS_SUB,  "OPTIONS",  literal_options,  "-options=",  TRSBS_IN_NONE                    )
+TRIGGER_SUBSDEF (DELIM_SUB,    "DELIM",    literal_delim,    "-delim=",    TRSBS_IN_BHASH                   )
+TRIGGER_SUBSDEF (ZDELIM_SUB,   "ZDELIM",   literal_zdelim,   "-zdelim=",   TRSBS_IN_BHASH                   )
+TRIGGER_SUBSDEF (PIECES_SUB,   "PIECES",   literal_pieces,   "-pieces=",   TRSBS_IN_BHASH                   )
+TRIGGER_SUBSDEF (XECUTE_SUB,   "XECUTE",   literal_xecute,   "-xecute=",   (TRSBS_IN_LHASH | TRSBS_IN_BHASH) )
+TRIGGER_SUBSDEF (CHSET_SUB,    "CHSET",    literal_chset,    "",           TRSBS_IN_NONE                    )
+TRIGGER_SUBSDEF (BHASH_SUB,    "BHASH",    literal_bhash,    "",           TRSBS_IN_NONE                    )
+TRIGGER_SUBSDEF (LHASH_SUB,    "LHASH",    literal_lhash,    "",           TRSBS_IN_NONE                    )
diff --git a/sr_unix/trigger_trgfile.c b/sr_unix/trigger_trgfile.c
index 071cc63..3f103da 100644
--- a/sr_unix/trigger_trgfile.c
+++ b/sr_unix/trigger_trgfile.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -24,9 +24,9 @@
 #include "hashtab_str.h"
 #include "trigger_trgfile_protos.h"
 #include "trigger_delete_protos.h"
+#include "trigger.h"			/* needed by "trigger_update_protos.h" for trig_stats_t prototype */
 #include "trigger_update_protos.h"
 #include "file_input.h"
-#include "trigger.h"
 #include "op.h"				/* for op_tstart */
 #include "op_tcommit.h"
 #include "gdscc.h"			/* needed for tp.h */
@@ -46,17 +46,22 @@
 #include "t_retry.h"
 #include "gtmimagename.h"
 
-#define TRIG_ERROR_RETURN						\
-{									\
-	if (lcl_implicit_tpwrap)					\
-	{	/* only if we were implicitly wrapped */		\
-		assert(dollar_tlevel);					\
-		assert(donot_INVOKE_MUMTSTART);				\
-		DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);		\
-		OP_TROLLBACK(-1);	/* Unroll implicit TP */	\
-		REVERT;							\
-	}								\
-	return TRIG_FAILURE;						\
+#define TRIG_ERROR_RETURN								\
+{											\
+	DCL_THREADGBL_ACCESS;								\
+											\
+	SETUP_THREADGBL_ACCESS;								\
+	if (lcl_implicit_tpwrap)							\
+	{	/* only if we were implicitly wrapped */				\
+		assert(dollar_tlevel);							\
+		assert(donot_INVOKE_MUMTSTART);						\
+		DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);				\
+		/* Print $ztrigger/mupip-trigger output before rolling back TP */	\
+		TP_ZTRIGBUFF_PRINT;							\
+		OP_TROLLBACK(-1);	/* Unroll implicit TP */			\
+		REVERT;									\
+	}										\
+	return TRIG_FAILURE;								\
 }
 
 GBLREF	sgm_info		*first_sgm_info;
@@ -74,15 +79,13 @@ GBLREF	unsigned char		t_fail_hist[CDB_MAX_TRIES];
 GBLREF	boolean_t		donot_INVOKE_MUMTSTART;
 #endif
 
-LITREF	mval			literal_hasht;
-
 error_def(ERR_DBROLLEDBACK);
 error_def(ERR_ZFILNMBAD);
 
 STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint4 trigger_filename_len, boolean_t noprompt,
 						    boolean_t lcl_implicit_tpwrap)
 {
-	boolean_t		all_triggers_error;
+	boolean_t		trigger_error;
 	uint4			i;
 	io_pair			io_save_device;
 	io_pair			io_trigfile_device;
@@ -95,18 +98,22 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
 	char			*values[NUM_SUBS];
 	unsigned short		value_len[NUM_SUBS];
 
-	all_triggers_error = FALSE;
 	if (lcl_implicit_tpwrap)
 		ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE);	/* Return through here is a failure */
 	io_save_device = io_curr_device;
-	file_input_init(trigger_filename, trigger_filename_len);
+	file_input_init(trigger_filename, trigger_filename_len, IOP_REWIND);
 	if (mupip_error_occurred)
+	{
+		assert(!memcmp(&io_curr_device, &io_save_device, SIZEOF(io_curr_device)));
+		io_curr_device = io_save_device;	/* just in case in PRO */
 		TRIG_ERROR_RETURN;
+	}
 	io_trigfile_device = io_curr_device;
 	record_num = 0;
 	for (i = 0; NUM_STATS > i; i++)
 		trig_stats[i] = 0;
-	while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec))))
+	trigger_error = FALSE;
+	while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec, 0))))
 	{
 		io_curr_device = io_save_device;
 		record_num++;
@@ -114,7 +121,9 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
 			util_out_print_gtmio("File !AD, Line !UL: ", NOFLUSH, trigger_filename_len, trigger_filename, record_num);
 		trigger_status = trigger_update_rec(trigger_rec, (uint4)len, noprompt, trig_stats, &io_trigfile_device,
 						    &record_num);
-		all_triggers_error |= (TRIG_FAILURE == trigger_status);
+		trigger_error |= (TRIG_FAILURE == trigger_status);
+		assert(!trigger_error || trig_stats[STATS_ERROR_TRIGFILE]);
+		assert(trigger_error || !trig_stats[STATS_ERROR_TRIGFILE]);
 		io_curr_device = io_trigfile_device;
 	}
 	if ((-1 == len) && (!io_curr_device.in->dollar.zeof))
@@ -122,44 +131,37 @@ STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint
 		io_curr_device = io_save_device;
 		util_out_print_gtmio("File !AD, Line !UL: Line too long", FLUSH, trigger_filename_len, trigger_filename,
 			++record_num);
+		io_curr_device = io_trigfile_device;
 	}
 	file_input_close();
 	io_curr_device = io_save_device;
-	if (all_triggers_error)
+	if (trigger_error)
 	{
 		util_out_print_gtmio("=========================================", FLUSH);
-		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
-		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
+		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR_TRIGFILE]);
 		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
-				     trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
+					trig_stats[STATS_NOERROR_TRIGFILE] + trig_stats[STATS_UNCHANGED_TRIGFILE]);
 		util_out_print_gtmio("=========================================", FLUSH);
-		TRIG_ERROR_RETURN;
-	}
-	if (lcl_implicit_tpwrap)
-	{
-		GVTR_OP_TCOMMIT(cdb_status);
-		if (cdb_sc_normal != cdb_status)
-			t_retry(cdb_status);	/* won't return */
-		REVERT;
+		TRIG_ERROR_RETURN;	/* rollback the trigger transaction due to errors and return */
 	}
-	if ((0 == trig_stats[STATS_ERROR])
-		&& (0 != (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED]
-			  + trig_stats[STATS_MODIFIED])))
+	if (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED_TRIGFILE] + trig_stats[STATS_MODIFIED])
 	{
 		util_out_print_gtmio("=========================================", FLUSH);
 		util_out_print_gtmio("!UL triggers added", FLUSH, trig_stats[STATS_ADDED]);
 		util_out_print_gtmio("!UL triggers deleted", FLUSH, trig_stats[STATS_DELETED]);
-		util_out_print_gtmio("!UL trigger file entries not changed", FLUSH, trig_stats[STATS_UNCHANGED]);
 		util_out_print_gtmio("!UL triggers modified", FLUSH, trig_stats[STATS_MODIFIED]);
+		util_out_print_gtmio("!UL trigger file entries did update database trigger content",
+					FLUSH, trig_stats[STATS_NOERROR_TRIGFILE]);
+		util_out_print_gtmio("!UL trigger file entries did not update database trigger content",
+					FLUSH, trig_stats[STATS_UNCHANGED_TRIGFILE]);
 		util_out_print_gtmio("=========================================", FLUSH);
-	} else if (0 != trig_stats[STATS_ERROR])
+	}
+	if (lcl_implicit_tpwrap)
 	{
-		util_out_print_gtmio("=========================================", FLUSH);
-		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
-		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
-		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
-			       trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
-		util_out_print_gtmio("=========================================", FLUSH);
+		GVTR_OP_TCOMMIT(cdb_status);	/* commit the trigger transaction */
+		if (cdb_sc_normal != cdb_status)
+			t_retry(cdb_status);	/* won't return */
+		REVERT;
 	}
 	return TRIG_SUCCESS;
 }
@@ -168,14 +170,13 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
 {
 	boolean_t		trigger_status = TRIG_FAILURE;
 	mval			ts_mv;
-	int			loopcnt;
+	int			loopcnt, utilbuff_len;
 	struct stat		statbuf;
 	DEBUG_ONLY(unsigned int	lcl_t_tries;)
 	enum cdb_sc		failure;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-
 	ts_mv.mvtype = MV_STR;
 	ts_mv.str.len = 0;
 	ts_mv.str.addr = NULL;
@@ -183,12 +184,19 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
 	assert('\0' == trigger_filename[trigger_filename_len]); /* should have been made sure by caller */
 	if (-1 == Stat(trigger_filename, &statbuf))
 	{
-		util_out_print_gtmio("Invalid file name: !AD: !AZ", FLUSH, trigger_filename_len, trigger_filename, STRERROR(errno));
+		DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = TRUE;)
+		util_out_print_gtmio("Invalid file name: !AD: !AZ",
+				FLUSH, trigger_filename_len, trigger_filename, STRERROR(errno));
+		DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = FALSE;)
+		TP_ZTRIGBUFF_PRINT;	/* Print $ztrigger/mupip-trigger output before returning */
 		return TRUE;	/* Failure */
 	} else if (!S_ISREG(statbuf.st_mode))
 	{
-		util_out_print_gtmio("Invalid file name: !AD: Not a proper input file", FLUSH, trigger_filename_len,
-				     trigger_filename);
+		DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = TRUE;)
+		util_out_print_gtmio("Invalid file name: !AD: Not a proper input file",
+						FLUSH, trigger_filename_len, trigger_filename);
+		DEBUG_ONLY(TREF(gtmio_skip_tlevel_assert) = FALSE;)
+		TP_ZTRIGBUFF_PRINT;	/* Print $ztrigger/mupip-trigger output before returning */
 		return TRUE;	/* Failure */
 	}
 	if (0 == dollar_tlevel)
@@ -199,7 +207,11 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
 		 * below after a successful op_tcommit of the $ZTRIGGER operation. We cannot check that dollar_tlevel is zero
 		 * since the op_tstart done below can be a nested sub-transaction
 		 */
-		op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+		op_tstart(IMPLICIT_TSTART, TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+		/* Note down length of unprocessed util_out buffer */
+		assert(NULL != TREF(util_outptr));
+		utilbuff_len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
+		assert(OUT_BUFF_SIZE >= utilbuff_len);
 		/* The following for loop structure is similar to that in module trigger_update.c (function "trigger_update")
 		 * and module gv_trigger.c (function gvtr_db_tpwrap) so any changes here might need to be reflected there as well.
 		 */
@@ -207,6 +219,8 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
 		{
 			assert(donot_INVOKE_MUMTSTART);	/* Make sure still set */
 			DEBUG_ONLY(lcl_t_tries = t_tries);
+			TREF(ztrigbuffLen) = utilbuff_len;	/* reset ztrig buffer at start of each try/retry */
+			TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal any unflushed text from previous try as gone */
 			trigger_status = trigger_trgfile_tpwrap_helper(trigger_filename, trigger_filename_len, noprompt, TRUE);
 			if (0 == dollar_tlevel)
 				break;
@@ -223,8 +237,6 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_
 			 * trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
 			 * actual trigger load
 			 */
-			util_out_print_gtmio("RESTART has invalidated this transaction's previous output.  New output follows.",
-					     FLUSH);
 			/* We expect the above function to return with either op_tcommit or a tp_restart invoked.
 			 * In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
 			 * In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
diff --git a/sr_unix/trigger_update.c b/sr_unix/trigger_update.c
index e641752..03c7870 100644
--- a/sr_unix/trigger_update.c
+++ b/sr_unix/trigger_update.c
@@ -34,7 +34,7 @@
 #include "mv_stent.h"			/* for COPY_SUBS_TO_GVCURRKEY macro */
 #include "gvsub2str.h"			/* for COPY_SUBS_TO_GVCURRKEY */
 #include "format_targ_key.h"		/* for COPY_SUBS_TO_GVCURRKEY */
-#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL & SWITCH_TO_DEFAULT_REGION */
+#include "targ_alloc.h"			/* for SET_GVTARGET_TO_HASHT_GBL */
 #include "gdsblk.h"
 #include "gdscc.h"			/* needed for tp.h */
 #include "gdskill.h"			/* needed for tp.h */
@@ -56,10 +56,13 @@
 #include "t_retry.h"
 #include "gtmimagename.h"
 #include "hashtab_mname.h"
+#include "zshow.h"		/* for "format2disp" prototype */
+#include "compiler.h"
 #include "t_begin.h"
 #include "repl_msg.h"
 #include "gtmsource.h"
-#include "zshow.h"
+#include "change_reg.h"		/* for "change_reg" prototype */
+#include "gvnh_spanreg.h"	/* for "gvnh_spanreg_subs_gvt_init" prototype */
 
 GBLREF	sgmnt_data_ptr_t	cs_data;
 GBLREF	sgm_info		*first_sgm_info;
@@ -80,40 +83,53 @@ GBLREF	boolean_t		donot_INVOKE_MUMTSTART;
 #endif
 
 error_def(ERR_DBROLLEDBACK);
+error_def(ERR_NEEDTRIGUPGRD);
+error_def(ERR_REMOTEDBNOTRIG);
 error_def(ERR_TEXT);
 error_def(ERR_TPRETRY);
 error_def(ERR_TPRETRY);
 error_def(ERR_TRIGDEFBAD);
 error_def(ERR_TRIGLOADFAIL);
-error_def(ERR_TRIGMODINTP);
 error_def(ERR_TRIGMODREGNOTRW);
-error_def(ERR_TRIGNOSPANGBL);
+error_def(ERR_TRIGNAMBAD);
 
 LITREF	mval			gvtr_cmd_mval[GVTR_CMDTYPES];
 LITREF	int4			gvtr_cmd_mask[GVTR_CMDTYPES];
-LITREF	mval			literal_hasht;
 LITREF	mval			literal_one;
 LITREF	char 			*trigger_subs[];
 
 #define	MAX_COMMANDS_LEN	32		/* Need room for S,K,ZK,ZTK + room for expansion */
 #define	MAX_OPTIONS_LEN		32		/* Need room for NOI,NOC + room for expansion */
 #define	MAX_TRIGNAME_SEQ_NUM	999999
+#define	MAX_TRIG_DISPLEN	80		/* maximum length of a trigger that is displayed in case of errors */
 #define	LITERAL_M		"M"
 #define	OPTIONS_I		1
 #define	OPTIONS_NOI		2
 #define	OPTIONS_C		4
 #define	OPTIONS_NOC		8
 
-#define	ADD_UPDATE_NOCHANGE	0x00
+#define	NO_NAME_CHANGE		0
+#define	NO_CMD_CHANGE		0
+#define	NO_OPTIONS_CHANGE	0
+
 #define	ADD_UPDATE_NAME		0x01
 #define	ADD_UPDATE_CMDS		0x02
 #define	ADD_UPDATE_OPTIONS	0x04
+
 #define	SUB_UPDATE_NAME		0x10
 #define	SUB_UPDATE_CMDS		0x20
-#define	SUB_UPDATE_OPTIONS	0x40
-#define	SUB_UPDATE_NOCHANGE	0x00
 #define	DELETE_REC		0x80
 
+/* Defines macros for types of triggers; one is SET type triggers, one is Non-SET type triggers */
+#define	OPR_KILL		0
+#define	OPR_SET			1
+#define	NUM_OPRS		2
+#define	OPR_SETKILL		2
+
+#define	SEQ_SUCCESS		0
+
+#define	MAX_HASH_LEN		MAX_HASH_INDEX_LEN + 1 + MAX_DIGITS_IN_INT
+
 #define	BUILD_COMMAND_BITMAP(BITMAP, COMMANDS)									\
 {														\
 	char		lcl_cmds[MAX_COMMANDS_LEN + 1];								\
@@ -167,24 +183,24 @@ LITREF	char 			*trigger_subs[];
 	} while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr));							\
 }
 
-#define	COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN)								\
-{														\
-	int		count, cmdtype, lcl_len;								\
-	char		*lcl_ptr;										\
-														\
-	count = 0;												\
-	lcl_ptr = COMMANDS;											\
-	lcl_len = LEN;												\
-	for (cmdtype = 0; cmdtype < GVTR_CMDTYPES; cmdtype++)							\
-	{													\
-		if (gvtr_cmd_mask[cmdtype] & (BITMAP))								\
-		{												\
-			ADD_COMMA_IF_NEEDED(count, lcl_ptr, lcl_len);						\
-			ADD_STRING(count, lcl_ptr, gvtr_cmd_mval[cmdtype].str.len, gvtr_cmd_mval[cmdtype].str.addr, lcl_len); \
-		}												\
-	}													\
-	*lcl_ptr = '\0';											\
-	LEN = STRLEN(COMMANDS);											\
+#define	COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN)										\
+{																\
+	int		count, cmdtype, lcl_len;										\
+	char		*lcl_ptr;												\
+																\
+	count = 0;														\
+	lcl_ptr = COMMANDS;													\
+	lcl_len = LEN;														\
+	for (cmdtype = 0; cmdtype < GVTR_CMDTYPES; cmdtype++)									\
+	{															\
+		if (gvtr_cmd_mask[cmdtype] & (BITMAP))										\
+		{														\
+			ADD_COMMA_IF_NEEDED(count, lcl_ptr, lcl_len);								\
+			ADD_STRING(count, lcl_ptr, gvtr_cmd_mval[cmdtype].str.len, gvtr_cmd_mval[cmdtype].str.addr, lcl_len);	\
+		}														\
+	}															\
+	*lcl_ptr = '\0';													\
+	LEN = STRLEN(COMMANDS);													\
 }
 
 #define	BUILD_OPTION_BITMAP(BITMAP, OPTIONS)									\
@@ -262,13 +278,15 @@ LITREF	char 			*trigger_subs[];
 	LEN = STRLEN(OPTIONS);											\
 }
 
-#define TOO_LONG_REC_KEY_ERROR_MSG										\
-{														\
-	trig_stats[STATS_ERROR]++;										\
-	if (KEY_TOO_LONG == result)										\
-		util_out_print_gtmio("^!AD trigger - key larger than max key size", FLUSH, trigvn_len, trigvn);	\
-	else													\
-		util_out_print_gtmio("^!AD trigger - value larger than max record size", FLUSH, trigvn_len, trigvn);	\
+#define TOO_LONG_REC_KEY_ERROR_MSG									\
+{													\
+	UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);				\
+	if (KEY_TOO_LONG == result)									\
+		util_out_print_gtmio("Error : ^!AD trigger - key larger than max key size",		\
+			FLUSH, disp_trigvn_len, disp_trigvn);						\
+	else												\
+		util_out_print_gtmio("Error : ^!AD trigger - value larger than max record size",	\
+			FLUSH, disp_trigvn_len, disp_trigvn);						\
 }
 
 #define IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(RESULT)						\
@@ -276,30 +294,27 @@ LITREF	char 			*trigger_subs[];
 	if (PUT_SUCCESS != RESULT)										\
 	{													\
 		TOO_LONG_REC_KEY_ERROR_MSG;									\
-		return TRIG_FAILURE;										\
+		return STATS_ERROR_TRIGFILE;									\
 	}													\
 }
 
-#define TRIGGER_SAME_NAME_EXISTS_ERROR												\
-{																\
-	trig_stats[STATS_ERROR]++;												\
-	util_out_print_gtmio("a trigger named !AD already exists", FLUSH, value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);	\
-	return TRIG_FAILURE;													\
-}
-
-/* This error macro is used for all definition errors where the target is ^#t(GVN,<index>,<required subscript>) */
-#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA)				\
-{												\
-	if (CDB_STAGNATE > t_tries)								\
-		t_retry(cdb_sc_triggermod);							\
-	else											\
-	{											\
-		assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);		\
-		/* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */	\
-		SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT);			\
-		rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,	\
-			trigvn_len, trigvn, util_len, util_buff);				\
-	}											\
+#define TRIGGER_SAME_NAME_EXISTS_ERROR(OPNAME, DISP_TRIGVN_LEN, DISP_TRIGVN)						\
+{															\
+	assert(dollar_tlevel);												\
+	if (CDB_STAGNATE > t_tries)											\
+	{	/* Directly jump to final retry since we cannot issue this error accurately				\
+		 * unless we are in the final retry. Dont waste time in intermediate tries.				\
+		 * But before then record the fact that the intermediate tries had normal status.			\
+		 */													\
+	 	for ( ; t_tries < (CDB_STAGNATE - 1); t_tries++)							\
+			t_fail_hist[t_tries] = cdb_sc_normal;								\
+		t_retry(cdb_sc_triggermod);										\
+	}														\
+	UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);						\
+	util_out_print_gtmio("Error : !AZ trigger on ^!AD not added as another trigger named !AD already exists",	\
+			FLUSH, OPNAME, DISP_TRIGVN_LEN, DISP_TRIGVN,							\
+			value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);							\
+	return STATS_ERROR_TRIGFILE;											\
 }
 
 /* This error macro is used for all definition errors where the target is ^#t(GVN,<#LABEL|#COUNT|#CYCLE>) */
@@ -351,37 +366,21 @@ STATICFNDEF int4 update_commands(char *trigvn, int trigvn_len, int trigger_index
 		new_trig_cmds, STRLEN(new_trig_cmds), result);
 	if (PUT_SUCCESS != result)
 		return result;
-	if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & orig_cmd_bm)) && (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & new_cmd_bm)))
+	if ((gvtr_cmd_mask[GVTR_CMDTYPE_SET] & orig_cmd_bm) && !(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & new_cmd_bm))
 	{	/* SET was removed from the commands, so delete the SET specific attributes */
-		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_DELIM, LITERAL_DELIM_LEN);
+		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+				trigger_subs[DELIM_SUB], STRLEN(trigger_subs[DELIM_SUB]));
 		gvcst_kill(TRUE);
-		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_ZDELIM, LITERAL_ZDELIM_LEN);
+		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+				trigger_subs[ZDELIM_SUB], STRLEN(trigger_subs[ZDELIM_SUB]));
 		gvcst_kill(TRUE);
-		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx, LITERAL_PIECES, LITERAL_PIECES_LEN);
+		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, mv_trig_indx,
+				trigger_subs[PIECES_SUB], STRLEN(trigger_subs[PIECES_SUB]));
 		gvcst_kill(TRUE);
 	}
-	trigger_incr_cycle(trigvn, trigvn_len);
 	return SUB_UPDATE_CMDS;
 }
 
-STATICFNDEF int4 update_options(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char *option_value)
-{
-	mval			mv_trig_indx;
-	int4			result;
-	DCL_THREADGBL_ACCESS;
-
-	SETUP_THREADGBL_ACCESS;
-	if (!validate_label(trigvn, trigvn_len))
-		return INVALID_LABEL;
-	i2mval(&mv_trig_indx, trigger_index);
-	SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, trigger_subs[OPTIONS_SUB],
-		STRLEN(trigger_subs[OPTIONS_SUB]), trig_options, STRLEN(trig_options), result);
-	if (PUT_SUCCESS != result)
-		return result;
-	trigger_incr_cycle(trigvn, trigvn_len);
-	return SUB_UPDATE_OPTIONS;
-}
-
 STATICFNDEF int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_index, char *db_trig_name, char *tf_trig_name,
 				     uint4 tf_trig_name_len)
 {
@@ -392,52 +391,178 @@ STATICFNDEF int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_i
 
 	SETUP_THREADGBL_ACCESS;
 	retval = NO_NAME_CHANGE;
-	if ((0 != tf_trig_name_len) && (tf_trig_name_len != STRLEN(db_trig_name) - 1)
-		|| (0 != memcmp(tf_trig_name, db_trig_name, tf_trig_name_len)))
+	if (tf_trig_name_len && (tf_trig_name_len != STRLEN(db_trig_name) - 1)
+		|| memcmp(tf_trig_name, db_trig_name, tf_trig_name_len))
 	{
 		if (!validate_label(trigvn, trigvn_len))
 			return INVALID_LABEL;
 		i2mval(&mv_trig_indx, trigger_index);
 		tf_trig_name[tf_trig_name_len++] = TRIGNAME_SEQ_DELIM;
-		SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, LITERAL_TRIGNAME, STRLEN(LITERAL_TRIGNAME),
-			tf_trig_name, tf_trig_name_len, result);
+		SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx,
+			trigger_subs[TRIGNAME_SUB], STRLEN(trigger_subs[TRIGNAME_SUB]), tf_trig_name, tf_trig_name_len, result);
 		if (PUT_SUCCESS != result)
 			return result;
 		cleanup_trigger_name(trigvn, trigvn_len, db_trig_name, STRLEN(db_trig_name));
-		trigger_incr_cycle(trigvn, trigvn_len);
 		retval = ADD_UPDATE_NAME;
 	}
 	return retval;
 }
 
-STATICFNDEF boolean_t check_unique_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, uint4 trigger_name_len)
+/*
+ * Input:	trigger_name and trigger_name_length
+ * 		[optional] srch_reg (when non-NULL this is the only region to search)
+ *
+ * Output:	returns TRUE if trigger name is found, false if not.
+ * 		srch_reg set to the region the name was found in.
+ * 		val is the "<gbl>\0<trigindx>" string to which the name points
+ *
+ * This function is similar to check_unique_trigger_name_full(), but is only called from
+ * trigger_source_read_andor_verify()
+ */
+boolean_t trigger_name_search(char *trigger_name, uint4 trigger_name_len, mval *val, gd_region **srch_reg)
 {
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
-	boolean_t		status;
-	mval			val;
+	boolean_t	name_found;
+	char		*ptr, *ptr2;
+	gd_region	*reg, *reg_top;
+	gd_region	*save_gv_cur_region;
+	gv_key		save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+	gv_namehead	*save_gv_target;
+	gvnh_reg_t	*gvnh_reg;
+	int		index, len;
+	mname_entry	gvname;
+	sgm_info	*save_sgm_info_ptr;
+
+	/* Example trigger name could be x#1#A:BREG to indicate trigger on global ^x with an autogenerated name x#1
+	 * that exists in multiple regions and hence had a runtime disambiguator of x#1#A. The :BREG is a region-level
+	 * disambiguator to indicate we want to focus on BREG region to search for triggers with the name x#1.
+	 * We dont expect the input trigger name to contain the runtime and region-level disambiguator but in case both
+	 * are present we treat it as if the runtime disambiguator was absent.
+	 */
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	/* Remove trailing # (if any) in trigger name before searching in ^#t as it is not stored in the ^#t("#TNAME",...) node */
+	assert('#' == trigger_name[trigger_name_len - 1]);
+	if ('#' == trigger_name[trigger_name_len - 1])
+		trigger_name_len--;
+	/* We only check user supplied names for uniqueness. With autogenerated names it is possible for
+	 * same name to exist in multiple regions (in case two globals with global name > 21 chars map to
+	 * different regions and have one trigger per global name installed with auto-generated names.
+	 * But even in that case, at most one auto-generated name per region is possible. So we have a limit
+	 * on the max # of duplicated auto-generated names.
+	 */
+	assert(0 < trigger_name_len);
+	SAVE_TRIGGER_REGION_INFO(save_currkey);
+	name_found = FALSE;
+	reg = *srch_reg;
+	if (NULL != reg)
+		reg_top = reg + 1;	/* make sure we dont go in the for loop more than once */
+	else
+	{
+		reg = gd_header->regions;
+		reg_top = reg + gd_header->n_regions;
+		assert(reg < reg_top);
+	}
+	for ( ; reg < reg_top; reg++)
+	{
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+		if (NULL == cs_addrs)	/* not BG or MM access method */
+			continue;
+		/* gv_target now points to ^#t in region "reg" */
+		if (0 == gv_target->root)
+			continue;
+		/* $get(^#t("#TNAME",trigger_name) */
+		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name, trigger_name_len);
+		if (!gvcst_get(val))
+			continue;
+		ptr = val->str.addr;
+		ptr2 = memchr(ptr, '\0', val->str.len);	/* Do it this way since "val" has multiple fields null separated */
+		if (NULL == ptr2)
+		{	/* We expect $c(0) in the middle of ptr. If we dont find it, this is a restartable situation */
+			if (CDB_STAGNATE > t_tries)
+				t_retry(cdb_sc_triggermod);
+			assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
+				trigger_name_len, trigger_name);
+		}
+		len = ptr2 - ptr;
+		assert(('\0' == *ptr2) && (val->str.len > len));
+		ptr2++;
+		A2I(ptr2, val->str.addr + val->str.len, index);
+		gvname.var_name.addr = val->str.addr;
+		gvname.var_name.len = len;
+		/* Check if global name is indeed mapped to this region by the gld.
+		 * If not treat this case as if the trigger is invisible to us i.e. move on to next region.
+		 */
+		COMPUTE_HASH_MNAME(&gvname);
+		GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);	/* does tp_set_sgm() */
+		if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
+				|| ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
+			continue;
+		*srch_reg = reg;
+		name_found = TRUE;
+		break;
+	}
+	RESTORE_TRIGGER_REGION_INFO(save_currkey);
+	return name_found;
+}
+
+/* Returns TRUE if name is NOT found. FALSE if name is found. If name is found, "val" holds the value of the found node */
+boolean_t check_unique_trigger_name_full(char **values, uint4 *value_len, mval *val, boolean_t *new_match,
+				char *trigvn, int trigvn_len, stringkey *kill_trigger_hash, stringkey *set_trigger_hash)
+{
+	boolean_t	overall_name_found, this_name_found;
+	gd_region	*reg, *reg_top;
+	gv_key		save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
+	gd_region	*save_gv_cur_region;
+	gv_namehead	*save_gv_target;
+	sgm_info	*save_sgm_info_ptr;
+	int		set_index, kill_index;
+	boolean_t	db_matched_set, db_matched_kill, full_match, trigger_exists;
+	mval		setname, killname;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	DEBUG_ONLY(if (WBTEST_HELPOUT_TRIGNAMEUNIQ == gtm_white_box_test_case_number) return TRUE;)
-	/* We only check user supplied names for uniqueness (since autogenerated names are unique). */
-	if (0 == trigger_name_len)
+	/* We only check user supplied names for uniqueness. With autogenerated names it is possible for
+	 * same name to exist in multiple regions (in case two globals with global name > 21 chars map to
+	 * different regions and have one trigger per global name installed with auto-generated names.
+	 * But even in that case, at most one auto-generated name per region is possible. So we have a limit
+	 * on the max # of duplicated auto-generated names.
+	 */
+	*new_match = TRUE;
+	if (0 == value_len[TRIGNAME_SUB])
 		return TRUE;
 	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	if (0 == gv_target->root)
+	overall_name_found = FALSE;
+	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
 	{
-		RESTORE_TRIGGER_REGION_INFO(save_currkey);
-		return TRUE;
+		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
+		if (NULL == cs_addrs)	/* not BG or MM access method */
+			continue;
+		/* gv_target now points to ^#t in region "reg" */
+		if (0 == gv_target->root)
+			continue;
+		/* $get(^#t("#TNAME",trigger_name) */
+		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME),
+			values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
+		this_name_found = gvcst_get(val);
+		if (this_name_found)
+		{
+			overall_name_found = TRUE;
+			trigger_exists = trigger_already_exists(trigvn, trigvn_len, values, value_len,
+								set_trigger_hash, kill_trigger_hash,
+								&set_index, &kill_index, &db_matched_set, &db_matched_kill,
+								&full_match, &setname, &killname);
+			if (!full_match)
+			{
+				*new_match = FALSE;
+				break;
+			}
+		}
 	}
-	/* $get(^#t("#TNAME",trigger_name) */
-	BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trigger_name, trigger_name_len);
-	status = !gvcst_get(&val);
 	RESTORE_TRIGGER_REGION_INFO(save_currkey);
-	return status;
+	return !overall_name_found;
 }
 
 STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_value, int trigindx, boolean_t add_kill_hash,
@@ -452,19 +577,13 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_
 	int			num_len;
 	char			*ptr;
 	int4			result;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
 	boolean_t		set_cmp;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
- 	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
+	assert(!gv_cur_region->read_only);	/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
 	set_cmp = (NULL != strchr(cmd_value, 'S'));
 	mv_indx_ptr = &mv_indx;
 	num_len = 0;
@@ -477,52 +596,52 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_
 	len = trigvn_len + 1 + num_len;
 	if (set_cmp)
 	{
-		MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
-		if (0 != gv_target->root)
-		{
-			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
-			op_zprevious(&mv_indx);
-			hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
-		} else
-			hash_indx = 1;
-		i2mval(&mv_indx, hash_indx);
-		SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx,
-			name_and_index,	len, result);
-		if (PUT_SUCCESS != result)
+		if (set_hash->hash_code != kill_hash->hash_code)
 		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
-			return result;
+			MV_FORCE_UMVAL(&mv_hash, set_hash->hash_code);
+			if (gv_target->root)
+			{
+				BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+					LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+				op_zprevious(&mv_indx);
+				hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
+			} else
+				hash_indx = 1;
+			i2mval(&mv_indx, hash_indx);
+			SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+				LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
+			if (PUT_SUCCESS != result)
+				return result;
 		}
+		/* else: the next block of code for kill hash processing will add this hashcode in ^#t("#TRHASH",...) */
 	} else
 		set_hash->hash_code = 0;
 	if (add_kill_hash)
 	{
 		MV_FORCE_UMVAL(&mv_hash, kill_hash->hash_code);
-		if (0 != gv_target->root)
+		if (gv_target->root)
 		{
-			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+			BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len,
+				LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
 			op_zprevious(&mv_indx);
 			hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
 		} else
 			hash_indx = 1;
 		i2mval(&mv_indx, hash_indx);
-		SET_TRIGGER_GLOBAL_SUB_MSUB_MSUB_STR(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx,
-			name_and_index,	len, result);
+		SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+			LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
 		if (PUT_SUCCESS != result)
-		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 			return result;
-		}
 	} else
 		kill_hash->hash_code = 0;
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
 	return PUT_SUCCESS;
 }
 
-STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, int *set_index,
-					     int *kill_index, boolean_t *set_cmp_result, boolean_t *kill_cmp_result,
-					     boolean_t *full_match, stringkey *set_trigger_hash, stringkey *kill_trigger_hash,
-					     mval *setname, mval *killname)
+STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len,	/* input parm */
+						stringkey *set_trigger_hash, stringkey *kill_trigger_hash,	/* input parm */
+						int *set_index, int *kill_index, boolean_t *set_cmp_result,	/* output parm */
+						boolean_t *kill_cmp_result, boolean_t *full_match,		/* output parm */
+						mval *setname, mval *killname)					/* output parm */
 {
 	sgmnt_addrs		*csa;
 	boolean_t		db_has_K;
@@ -532,156 +651,147 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char
 	boolean_t		kill_cmp, kill_found;
 	int			kill_indx;
 	boolean_t		name_match;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
 	boolean_t		set_cmp, set_found, set_name_match, kill_name_match;
 	int			set_indx;
 	mval			trigindx;
-	unsigned char		util_buff[MAX_TRIG_UTIL_LEN];
+	unsigned char		util_buff[MAX_TRIG_UTIL_LEN];	/* needed for HASHT_GVN_DEFINITION_RETRY_OR_ERROR macro */
 	int4			util_len;
 	mval			val;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	/* test with SET and/or KILL hash */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
+	assert(gv_target->root);			/* should have been ensured by caller */
+	/* Test with BHASH or LHASH.
+	 *	^#t("GBL",1,"CMD") could contain one or more of "S,K,ZK,ZTK,ZTR".
+	 * Out of the 5 commands above, a S type trigger uses the "BHASH" hash value.
+	 * Everything else (K, ZK, ZTK, ZTR) uses the "LHASH" value.
+	 * An easy check of one of these 4 commands is a chek for the letter K or R.
+	 */
 	set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
 	kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
 	set_found = kill_found = set_name_match = kill_name_match = FALSE;
 	csa = cs_addrs;
 	if (set_cmp)
-	{ /* test for SET hash match if SET command specified */
-		set_found = search_triggers(trigvn, trigvn_len, values, value_len, set_trigger_hash, &hash_indx, &set_indx, 0,
-				TRUE);
+	{	/* test for SET hash match if SET command specified */
+		set_found = search_triggers(trigvn, trigvn_len, values, value_len, set_trigger_hash, &hash_indx, &set_indx, TRUE);
 		if (set_found)
 		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 			i2mval(&trigindx, set_indx);
 			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
 					STRLEN(trigger_subs[TRIGNAME_SUB]));
 			if (!gvcst_get(setname)) /* There has to be a name value */
 				HASHT_GVN_DEFINITION_RETRY_OR_ERROR(set_indx, ",\"TRIGNAME\"", csa);
-			set_name_match = ((value_len[TRIGNAME_SUB] == (setname->str.len - 1))
-				&& (0 == memcmp(setname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB])));
+			setname->str.len--;	/* remove the # at the tail of the trigger name */
+			set_name_match = ((value_len[TRIGNAME_SUB] == setname->str.len)
+				&& !memcmp(setname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]));
 		}
-	}
+	} else
+		set_indx = 0;
 	*set_cmp_result = set_found;
+	kill_indx = -1;
 	if (kill_cmp || !set_found)
-	{ /* if SET is not found OR KILL is specified in commands, test for KILL hash match */
-		kill_found = search_triggers(trigvn, trigvn_len, values, value_len, kill_trigger_hash, &hash_indx, &kill_indx, 0,
-				FALSE);
+	{	/* if SET is not found OR KILL is specified in commands, test for KILL hash match */
+		kill_found = search_triggers(trigvn, trigvn_len, values, value_len, kill_trigger_hash,
+										&hash_indx, &kill_indx, FALSE);
 		if (kill_found)
 		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
-			i2mval(&trigindx, kill_indx);
-			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB],
-							 STRLEN(trigger_subs[CMD_SUB]));
-			if (!gvcst_get(&val))	/* There has to be a command string */
-				HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"CMD\"", csa);
-			db_has_S = (NULL != memchr(val.str.addr, 'S', val.str.len));
-			db_has_K = ((NULL != memchr(val.str.addr, 'K', val.str.len)) ||
-				    (NULL != memchr(val.str.addr, 'R', val.str.len)));
-			/* Below means
-			 * NOT ( Matched trigger has SET && New trigger has SET &&
-			 * 	NOT ( Matched trigger has SET + KILL && New trigger has SET + KILL )  )
-			 *
-			 * KILL is found if:
-			 * The matched trigger does not have a SET || The new trigger does not have a SET
-			 * But not if the matched trigger has a SET or KILL && the new trigger does not have a SET or KILL
-			 */
-			kill_found = !(db_has_S && set_cmp && !(db_has_S && db_has_K && set_cmp && kill_cmp));
-			/* $get(^#t(trigvn,trigindx,"TRIGNAME") */
-			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
-							 STRLEN(trigger_subs[TRIGNAME_SUB]));
-			if (!gvcst_get(killname)) /* There has to be a name string */
-				HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"TRIGNAME\"", csa);
-			kill_name_match = ((value_len[TRIGNAME_SUB] == (killname->str.len - 1))
-				&& (0 == memcmp(killname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB])));
-		}
-	}
-	/* Starting from the beginning:
-	 *    Matching both set and kill, but for different records -- don't update the kill record, hence the FALSE
-	 *    Matching a set implies matching a kill -- hence the ||
-	 */
-	if (set_found && kill_found && (set_indx != kill_indx))
-	{
-		*kill_cmp_result = FALSE;
-		*kill_index = kill_indx;
-	} else
-	{
-		*kill_cmp_result = (kill_found || set_found);
-		if (!set_found)
+			if (!set_found || (kill_indx != set_indx))
+			{
+				i2mval(&trigindx, kill_indx);
+				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB],
+								 STRLEN(trigger_subs[CMD_SUB]));
+				if (!gvcst_get(&val))	/* There has to be a command string */
+					HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"CMD\"", csa);
+				/* val.str.addr would contain something like the following
+				 *	^#t("GBL",1,"CMD")="S,K,ZK,ZTK,ZTR".
+				 * Out of the 5 commands above, a S type trigger uses the "BHASH" hash value.
+				 * Everything else (K, ZK, ZTK, ZTR) uses the "LHASH" value.
+				 */
+				db_has_S = (NULL != memchr(val.str.addr, 'S', val.str.len));
+				db_has_K = ((NULL != memchr(val.str.addr, 'K', val.str.len))
+						|| (NULL != memchr(val.str.addr, 'R', val.str.len)));
+				if (!kill_cmp)
+					kill_found = (db_has_K && !db_has_S);
+				/* $get(^#t(trigvn,trigindx,"TRIGNAME") */
+				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[TRIGNAME_SUB],
+								 STRLEN(trigger_subs[TRIGNAME_SUB]));
+				if (!gvcst_get(killname)) /* There has to be a name string */
+					HASHT_GVN_DEFINITION_RETRY_OR_ERROR(kill_indx, ",\"TRIGNAME\"", csa);
+				killname->str.len--;	/* remove the # at the tail of the trigger name */
+				kill_name_match = ((value_len[TRIGNAME_SUB] == killname->str.len)
+					&& !memcmp(killname->str.addr, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]));
+				if (set_cmp && !set_found && !db_has_S)
+				{
+					*setname = *killname;
+					set_indx = kill_indx;
+				}
+			} else
+				*killname = *setname;
+		} else
 		{
-			setname->mvtype = MV_STR;
-			setname->str.addr = killname->str.addr;
-			setname->str.len = killname->str.len;
+			kill_indx = -1;
+			if (!set_found)
+				set_indx = 0;
 		}
+		if (set_cmp && (kill_indx == set_indx))
+			kill_indx = -1;
 	}
-	*set_index = (set_found) ? set_indx : (kill_found) ? kill_indx : 0;
+	*kill_index = kill_indx;
+	*kill_cmp_result = kill_found ? TRUE : set_found;
+	*set_index = set_indx;
 	/* If there is both a set and a kill and the set components don't match, there is no name match no matter if the kill
 	 * components match or not.  If there is no set, then the name match is only based on the kill components.
 	 */
-	*full_match = (set_cmp) ? set_name_match : kill_name_match;
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
+	*full_match = (set_cmp ? set_name_match : kill_name_match);
 	return (set_found || kill_found);
 }
 
-STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len,  int trigger_index, char *trig_cmds, char **values,
-			uint4 *value_len, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash, stringkey *set_hash)
+STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_cmds, char **values,
+		uint4 *value_len, boolean_t db_matched_set, boolean_t db_matched_kill, stringkey *kill_hash, stringkey *set_hash,
+		uint4 db_cmd_bm, uint4 tf_cmd_bm)
 {
 	char			cmd_str[MAX_COMMANDS_LEN];
 	int			cmd_str_len;
-	uint4			db_cmd_bm;
 	mval			mv_hash;
 	mval			mv_trig_indx;
 	int4			result;
-	uint4			tf_cmd_bm;
 	uint4			tmp_bm;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	if (!validate_label(trigvn, trigvn_len))
 		return INVALID_LABEL;
-	BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
-	BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
 	/* If the trigger file command string is contained in the database command and either
 	 *   1. the trigger file command has no SET components or
-	 *   2. the trigger file command matched a database SET component or
+	 *   2. the trigger file command matched a database SET component
 	 * then the trigger file command is already in the database, so return.
 	 */
-	if ((tf_cmd_bm == (db_cmd_bm & tf_cmd_bm))
-			&& ((0 == (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) || set_compare))
-		return CMDS_PRESENT;
-	/* If the database command string is contained in the trigger file command and the database is only a "SET"
-	 * and the trigger file SET matched the database, but not the KILL (which doesn't make sense until you realize that
-	 * trigger_already_exists() returns kill_compare as FALSE when the trigger file record matches both SET and KILL, but
-	 * the matches are with two different triggers, then the trigger file command is already in the database so return.
-	 */
-	if ((db_cmd_bm == (db_cmd_bm & tf_cmd_bm))
-			&& ((db_cmd_bm == (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) && set_compare && !kill_compare))
-		return CMDS_PRESENT;
+	if ((tf_cmd_bm == (db_cmd_bm & tf_cmd_bm)) && (!(tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]) || db_matched_set))
+		return NO_CMD_CHANGE;
+	assert(!db_matched_set || db_matched_kill);
 	/* If merge would combine K and ZTK, it's an error */
-	if (((0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL])) && (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL])))
-	    || ((0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL])) && (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL]))))
+	if (((db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL]) && (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL]))
+			|| ((db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_ZTKILL]) && (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_KILL])))
 		return K_ZTK_CONFLICT;
-	if (!set_compare && kill_compare
-		&& (0 != (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])) && (0 != (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET])))
-	{	/* Subtract common (between triggerfile and DB) "non-S" from tf_cmd_bm */
-		tmp_bm = gvtr_cmd_mask[GVTR_CMDTYPE_SET];
-		COMMAND_BITMAP_TO_STR(values[CMD_SUB], tmp_bm, value_len[CMD_SUB]);
-		/* since the KILL matches, update the corresponding trigger's KILLs */
-		tmp_bm = db_cmd_bm | (tf_cmd_bm ^ (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm));
+	if (!db_matched_set && db_matched_kill
+		&& (tf_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]) && (db_cmd_bm & gvtr_cmd_mask[GVTR_CMDTYPE_SET]))
+	{
+		tmp_bm = (db_cmd_bm | tf_cmd_bm);
+		if (tmp_bm == db_cmd_bm)
+		{	/* No change to commands in the KILL trigger entry in db.
+			 * SET trigger (if it exists and is in a different trigger) to be processed separately.
+			 */
+			return ADD_SET_NOCHNG_KILL_TRIG;
+		}
+		/* Commands are being added to the existing KILL trigger entry in db */
 		cmd_str_len = ARRAYSIZE(cmd_str);
 		COMMAND_BITMAP_TO_STR(cmd_str, tmp_bm, cmd_str_len);
 		i2mval(&mv_trig_indx, trigger_index);
 		SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_STR(trigvn, trigvn_len, mv_trig_indx, trigger_subs[CMD_SUB],
 						    STRLEN(trigger_subs[CMD_SUB]), cmd_str, cmd_str_len, result);
 		assert(result == PUT_SUCCESS);
-		return (result == PUT_SUCCESS) ? ADD_NEW_TRIGGER : result;
+		return (result == PUT_SUCCESS) ? ADD_SET_MODIFY_KILL_TRIG : result;
 	}
 	cmd_str_len = ARRAYSIZE(cmd_str);
 	COMMAND_BITMAP_TO_STR(cmd_str, db_cmd_bm | tf_cmd_bm, cmd_str_len);
@@ -691,7 +801,7 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len,  int t
 	if (PUT_SUCCESS != result)
 		return result;
 	strcpy(trig_cmds, cmd_str);
-	if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)) && (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm)))
+	if ((gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm) && !(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
 	{	/* need to add SET attributes */
 		if (0 < value_len[DELIM_SUB])
 		{
@@ -714,8 +824,7 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len,  int t
 			if (PUT_SUCCESS != result)
 				return result;
 		}
-		if ((0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
-			&& (0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)))
+		if (!(gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm) && (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm))
 		{	/* We gained an "S" so we need to add the set hash value */
 			result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], trigger_index, FALSE, kill_hash,
 					set_hash);
@@ -728,7 +837,6 @@ STATICFNDEF int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len,  int t
 				return result;
 		}
 	}
-	trigger_incr_cycle(trigvn, trigvn_len);
 	return ADD_UPDATE_CMDS;
 }
 
@@ -747,14 +855,10 @@ STATICFNDEF int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, in
 	SETUP_THREADGBL_ACCESS;
 	BUILD_OPTION_BITMAP(db_option_bm, trig_options);
 	BUILD_OPTION_BITMAP(tf_option_bm, values[OPTIONS_SUB]);
-	if (tf_option_bm == (db_option_bm & tf_option_bm))
+	if (tf_option_bm == db_option_bm)
 		/* If trigger file OPTIONS is contained in the DB OPTIONS, then trigger file entry is already in DB, just return */
-		return OPTIONS_PRESENT;
-	tmp_bm = db_option_bm | tf_option_bm;
-	if (((0 != (OPTIONS_C & tmp_bm)) && (0 != (OPTIONS_NOC & tmp_bm)))
-			|| ((0 != (OPTIONS_I & tmp_bm)) && (0 != (OPTIONS_NOI & tmp_bm))))
-		/* Can't combine incompatible options, so triggers are different */
-		return OPTION_CONFLICT;
+		return NO_OPTIONS_CHANGE;
+	tmp_bm = tf_option_bm;
 	if (!validate_label(trigvn, trigvn_len))
 		return INVALID_LABEL;
 	option_str_len = ARRAYSIZE(option_str);
@@ -765,88 +869,50 @@ STATICFNDEF int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, in
 	if (PUT_SUCCESS != result)
 		return result;
 	strcpy(trig_options, option_str);
-	trigger_incr_cycle(trigvn, trigvn_len);
 	return ADD_UPDATE_OPTIONS;
 }
 
 STATICFNDEF boolean_t subtract_trigger_cmd_attributes(char *trigvn, int trigvn_len, char *trig_cmds, char **values,
-		uint4 *value_len, boolean_t set_cmp, stringkey *kill_hash, stringkey *set_hash)
+		uint4 *value_len, boolean_t db_matched_set, stringkey *kill_hash, stringkey *set_hash, int trigger_index,
+		uint4 db_cmd_bm, uint4 tf_cmd_bm)
 {
 	char			cmd_str[MAX_COMMANDS_LEN];
 	int			cmd_str_len;
-	uint4			db_cmd_bm;
 	uint4			len;
-	uint4			tf_cmd_bm;
 	uint4			restore_set = 0;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
-	BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
-	if (!set_cmp && (0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm)))
-	{ /* If the set compare failed, we don't want to consider the SET */
+	if (!db_matched_set && (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & tf_cmd_bm))
+	{	/* If the set compare failed, we don't want to consider the SET */
 		restore_set = gvtr_cmd_mask[GVTR_CMDTYPE_SET];
 		tf_cmd_bm &= ~restore_set;
 	}
 	if (0 == (db_cmd_bm & tf_cmd_bm))
-		/* If trigger file CMD does NOT overlap with the DB CMD, then no match. So no delete.  Just return */
-		return 0;
+		return 0; /* If trigger file CMD does NOT overlap with the DB CMD, then no match. So no delete. Just return */
 	cmd_str_len = ARRAYSIZE(cmd_str);
 	if (db_cmd_bm != (db_cmd_bm & tf_cmd_bm))
 	{	/* combine cmds - subtract trigger file attributes from db attributes */
 		COMMAND_BITMAP_TO_STR(cmd_str, (db_cmd_bm & tf_cmd_bm) ^ db_cmd_bm, cmd_str_len);
 		strcpy(trig_cmds, cmd_str);
+		/* If we lost the "S", need to delete the set hash value */
 		if ((0 != (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & db_cmd_bm))
 				&& (0 == (gvtr_cmd_mask[GVTR_CMDTYPE_SET] & ((db_cmd_bm & tf_cmd_bm) ^ db_cmd_bm))))
-			/* We lost the "S" so we need to delete the set hash value */
-			cleanup_trigger_hash(trigvn, trigvn_len, values, value_len, set_hash, kill_hash, FALSE, 0);
+			cleanup_trigger_hash(trigvn, trigvn_len, values, value_len, set_hash, kill_hash, FALSE, trigger_index);
 	} else
 	{	/* Both cmds are the same - candidate for delete */
 		trig_cmds[0] = '\0';
 		db_cmd_bm |= restore_set;
-		COMMAND_BITMAP_TO_STR(cmd_str, db_cmd_bm, cmd_str_len);
-		value_len[CMD_SUB] = cmd_str_len;
-		strcpy(values[CMD_SUB], cmd_str);
-
 	}
 	return SUB_UPDATE_CMDS;
 }
 
-STATICFNDEF boolean_t subtract_trigger_options_attributes(char *trigvn, int trigvn_len, char *trig_options, char *option_value)
-{
-	uint4			db_option_bm;
-	char			option_str[MAX_OPTIONS_LEN];
-	int			option_str_len;
-	uint4			tf_option_bm;
-	uint4			tmp_bm;
-	DCL_THREADGBL_ACCESS;
-
-	SETUP_THREADGBL_ACCESS;
-	BUILD_OPTION_BITMAP(db_option_bm, trig_options);
-	BUILD_OPTION_BITMAP(tf_option_bm, option_value);
-	if (((0 != db_option_bm) && (0 != tf_option_bm)) && (0 == (db_option_bm & tf_option_bm)))
-		/* If trigger file OPTIONS does NOT overlap with the DB OPTIONS, then no match. So no delete.  Just return */
-		return 0;
-	if (db_option_bm != (db_option_bm & tf_option_bm))
-	{
-		/* combine options - subtract trigger file attributes from db attributes */
-		tmp_bm = (db_option_bm & tf_option_bm) ^ db_option_bm;
-		assert((0 == (OPTIONS_C & tmp_bm)) || (0 == (OPTIONS_NOC & tmp_bm)));
-		assert((0 == (OPTIONS_I & tmp_bm)) || (0 == (OPTIONS_NOI & tmp_bm)));
-		option_str_len = ARRAYSIZE(option_str);
-		OPTION_BITMAP_TO_STR(option_str, tmp_bm, option_str_len);
-		strcpy(trig_options, option_str);
-	} else
-		/* Both options are the same - candidate to delete */
-		trig_options[0] = '\0';
-	return SUB_UPDATE_OPTIONS;
-}
-
 STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, int trigger_index, char **values, uint4 *value_len,
-		mval *trigger_count, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash, stringkey *set_hash)
+		mval *trigger_count, boolean_t db_matched_set, boolean_t db_matched_kill,
+		stringkey *kill_hash, stringkey *set_hash, int set_kill_bitmask)
 {
 	char			db_cmds[MAX_COMMANDS_LEN + 1];
-	boolean_t		name_matches;
+	boolean_t		name_matches, sub_cmds;
 	int4			result;
 	uint4			retval;
 	mval			trigindx;
@@ -856,16 +922,26 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in
 	unsigned char		util_buff[MAX_TRIG_UTIL_LEN];
 	int4			util_len;
 	mval			val;
+	uint4			db_cmd_bm, tf_cmd_bm;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	retval = 0;
 	i2mval(&trigindx, trigger_index);
+	/* get(^#t(GVN,trigindx,"CMD") */
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[CMD_SUB], STRLEN(trigger_subs[CMD_SUB]));
 	if (!gvcst_get(&val)) /* There has to be a command string */
 		HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigger_index, ",\"CMD\"", REG2CSA(gv_cur_region));
 	memcpy(trig_cmds, val.str.addr, val.str.len);
 	trig_cmds[val.str.len] = '\0';
+	BUILD_COMMAND_BITMAP(db_cmd_bm, trig_cmds);
+	BUILD_COMMAND_BITMAP(tf_cmd_bm, values[CMD_SUB]);
+	/* If trigger file has specified SET and/or KILL triggers and each of them matched to different triggers in database,
+	 * filter out only the respective category of triggers to go forward with the command addition/deletion.
+	 */
+	if (OPR_KILL == set_kill_bitmask)
+		tf_cmd_bm &= ~gvtr_cmd_mask[GVTR_CMDTYPE_SET];
+	else if (OPR_SET == set_kill_bitmask)
+		tf_cmd_bm &= gvtr_cmd_mask[GVTR_CMDTYPE_SET];
 	/* get(^#t(GVN,trigindx,"OPTIONS") */
 	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigindx, trigger_subs[OPTIONS_SUB],
 		STRLEN(trigger_subs[OPTIONS_SUB]));
@@ -884,72 +960,74 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in
 	trig_name[val.str.len] = '\0';
 	if ('+' == add_delete)
 	{
-		result = add_trigger_cmd_attributes(trigvn, trigvn_len, trigger_index, trig_cmds, values, value_len,
-						    set_compare, kill_compare, kill_hash, set_hash);
-		switch (result)
-		{
-			case K_ZTK_CONFLICT:
-			case INVALID_LABEL:
-			case ADD_NEW_TRIGGER:
-			case VAL_TOO_LONG:
-			case KEY_TOO_LONG:
-				return result;
-			default:
-				retval = result;
+		/* Process -OPTIONS */
+		result = add_trigger_options_attributes(trigvn, trigvn_len, trigger_index, trig_options, values, value_len);
+		assert((NO_OPTIONS_CHANGE == result) || (ADD_UPDATE_OPTIONS == result)				  /* 0 or 0x04 */
+			|| (INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result));	  /* < 0 */
+		if (0 > result)
+			return result;
+		assert((NO_OPTIONS_CHANGE == result) || (ADD_UPDATE_OPTIONS == result));
+		if (NO_OPTIONS_CHANGE != result)
+		{	/* Check if specified list of commands matches commands in database. If not cannot proceed */
+			if (tf_cmd_bm != db_cmd_bm)
+				return OPTIONS_CMDS_CONFLICT;
 		}
+		retval = result;
+		/* Process -NAME */
 		result = update_trigger_name(trigvn, trigvn_len, trigger_index, trig_name, values[TRIGNAME_SUB],
 					     value_len[TRIGNAME_SUB]);
-		if ((INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
+		assert((NO_NAME_CHANGE == result) || (ADD_UPDATE_NAME == result)				  /* 0 or 0x01 */
+			|| (INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result));	  /* < 0 */
+		if (0 > result)
 			return result;
+		assert((NO_NAME_CHANGE == result) || (ADD_UPDATE_NAME == result));
+		if (NO_NAME_CHANGE != result)
+		{	/* Check if specified list of commands contains commands in database. If not cannot proceed */
+			if ((tf_cmd_bm &db_cmd_bm) != db_cmd_bm)
+				return NAME_CMDS_CONFLICT;
+		}
 		retval |= result;
-		result = add_trigger_options_attributes(trigvn, trigvn_len, trigger_index, trig_options, values, value_len);
-		if ((INVALID_LABEL == result) || (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
+		/* Process -CMD */
+		result = add_trigger_cmd_attributes(trigvn, trigvn_len, trigger_index, trig_cmds, values, value_len,
+						    db_matched_set, db_matched_kill, kill_hash, set_hash, db_cmd_bm, tf_cmd_bm);
+		assert((NO_CMD_CHANGE == result) || (ADD_UPDATE_CMDS == result)				 /* 0 or 0x02 */
+			|| (ADD_SET_MODIFY_KILL_TRIG == result) || (ADD_SET_NOCHNG_KILL_TRIG == result)	 /* < 0 */
+			|| (INVALID_LABEL == result) || (K_ZTK_CONFLICT == result)			 /* < 0 */
+			|| (VAL_TOO_LONG == result) || (KEY_TOO_LONG == result));			 /* < 0 */
+		if (0 > result)
 			return result;
+		assert((NO_CMD_CHANGE == result) || (ADD_UPDATE_CMDS == result));
 		retval |= result;
 	} else
 	{
 		name_matches = (0 == value_len[TRIGNAME_SUB])
-			|| ((value_len[TRIGNAME_SUB] == (STRLEN(trig_name) - 1))
-				&& (0 == memcmp(values[TRIGNAME_SUB], trig_name, value_len[TRIGNAME_SUB])));
-		if (name_matches)
+					|| ((value_len[TRIGNAME_SUB] == (STRLEN(trig_name) - 1))
+						&& (0 == memcmp(values[TRIGNAME_SUB], trig_name, value_len[TRIGNAME_SUB])));
+		if (!name_matches)
+			return 0;
+		memcpy(db_cmds, trig_cmds, SIZEOF(trig_cmds));
+		sub_cmds = subtract_trigger_cmd_attributes(trigvn, trigvn_len, trig_cmds, values, value_len,
+							db_matched_set, kill_hash, set_hash, trigger_index, db_cmd_bm, tf_cmd_bm);
+		/* options are ignored in case of deletes so no need for "subtract_trigger_options_attributes()" */
+		if (!sub_cmds)
+			return 0;
+		if (0 == trig_cmds[0])
 		{
-			retval = SUB_UPDATE_NAME;
-			memcpy(db_cmds, trig_cmds, SIZEOF(trig_cmds));
-			retval |= subtract_trigger_cmd_attributes(trigvn, trigvn_len, trig_cmds, values, value_len, set_compare,
-					kill_hash, set_hash);
-			retval |= subtract_trigger_options_attributes(trigvn, trigvn_len, trig_options, values[OPTIONS_SUB]);
+			result = trigger_delete(trigvn, trigvn_len, trigger_count, trigger_index);
+			assert((VAL_TOO_LONG == result) || (KEY_TOO_LONG == result)			/*  < 0 */
+					|| (PUT_SUCCESS == result));					/* == 0 */
+			if (0 > result)
+				return result;
+			return DELETE_REC;
 		}
-		if ((0 != (retval & SUB_UPDATE_NAME)) && (0 != (retval & SUB_UPDATE_OPTIONS)) && (0 != (retval & SUB_UPDATE_CMDS)))
+		retval = 0;
+		if (sub_cmds)
 		{
-			if ((0 == trig_cmds[0]) && (0 == trig_options[0]))
-			{
-				result = trigger_delete(trigvn, trigvn_len, trigger_count, trigger_index);
-				if ((VAL_TOO_LONG == result) || (KEY_TOO_LONG == result))
-					return result;
-				retval = DELETE_REC;
-			} else
-			{
-				retval = 0;
-				if (0 != trig_cmds[0])
-				{
-					result = update_commands(trigvn, trigvn_len, trigger_index, trig_cmds, db_cmds);
-					if (SUB_UPDATE_CMDS != result)
-						return result;
-					retval |= result;
-				}
-				if (0 != trig_options[0])
-				{
-					result = update_options(trigvn, trigvn_len, trigger_index, trig_options,
-								values[OPTIONS_SUB]);
-					if (SUB_UPDATE_OPTIONS != result)
-						return result;
-					if (0 != value_len[OPTIONS_SUB])
-						retval |= result;
-				}
-			}
+			result = update_commands(trigvn, trigvn_len, trigger_index, trig_cmds, db_cmds);
+			if (SUB_UPDATE_CMDS != result)
+				return result;
+			retval |= result;
 		}
-		else
-			retval = SUB_UPDATE_NOCHANGE;
 	}
 	return retval;
 }
@@ -961,102 +1039,83 @@ STATICFNDEF int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigg
 	char			*ptr1;
 	int			rndm_int;
 	int			seq_num;
-	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
-	gd_region		*save_gv_cur_region;
-	gv_namehead		*save_gv_target;
-	sgm_info		*save_sgm_info_ptr;
 	int4			result;
 	char			*seq_ptr, *uniq_ptr;
 	char			trig_name[MAX_USER_TRIGNAME_LEN + 1];
-	uint4			trigname_len;
+	uint4			trigname_len, uniq_ptr_len;
 	char			unique_seq_str[NUM_TRIGNAME_SEQ_CHARS + 1];
 	mval			val, *val_ptr;
 	char			val_str[MAX_DIGITS_IN_INT + 1];
-	int			var_count;
+	int			var_count, max_seq_num;
+	mval			label, *label_mv;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	assert(MAX_USER_TRIGNAME_LEN >= user_trigname_len);
-	uniq_ptr = unique_seq_str;
-	seq_num = 1;
+	assert(!gv_cur_region->read_only);	/* caller should have already checked this */
+	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
 	if (0 == user_trigname_len)
-	{	/* autogenerated name  -- might be long */
+	{	/* autogenerated name  -- might be long so take MIN */
 		trigname_len = MIN(trigvn_len, MAX_AUTO_TRIGNAME_LEN);
 		strncpy(trig_name, trigvn, trigname_len);
-	} else
-	{	/* user supplied name */
-		trigname_len = user_trigname_len;
-		strncpy(trig_name, user_trigname_str, user_trigname_len);
-	}
-	SAVE_TRIGGER_REGION_INFO(save_currkey);
-	SWITCH_TO_DEFAULT_REGION;
-	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
-	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	if (0 == user_trigname_len)
-	{	/* autogenerated name */
 		val_ptr = &val;
-		if (0 != gv_target->root)
-		{
-			/* $get(^#t("#TNAME",GVN,"#SEQCOUNT")) */
-			BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
-				LITERAL_HASHSEQNUM, STRLEN(LITERAL_HASHSEQNUM));
+		if (gv_target->root)
+		{	/* $get(^#t("#TNAME",GVN,"#SEQNUM")) */
+			BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+				LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM));
 			seq_num = gvcst_get(val_ptr) ? mval2i(val_ptr) + 1 : 1;
-			if (MAX_TRIGNAME_SEQ_NUM < seq_num)
-			{
-				RESTORE_TRIGGER_REGION_INFO(save_currkey);
+			max_seq_num = MAX_TRIGNAME_SEQ_NUM;
+			/* If dbg & white-box test then reduce limit to 1000 (instead of 1 million) auto-generated trigger names */
+			if (WBTEST_ENABLED(WBTEST_MAX_TRIGNAME_SEQ_NUM))
+				max_seq_num = 999;
+			if (max_seq_num < seq_num)
 				return TOO_MANY_TRIGGERS;
-			}
+		} else
+		{
+			/* Set ^#t("#LABEL")=3 */
+			label_mv = &label;
+			MV_FORCE_MVAL(label_mv, 3);
+			SET_TRIGGER_GLOBAL_SUB_MVAL(LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL), label, result);
+			seq_num = 1;
 		}
+		uniq_ptr = unique_seq_str;
 		INT2STR(seq_num, uniq_ptr);
-		/* set ^#t("#TNAME",GVN,"#SEQCOUNT")++ via unique_seq_str which came from seq_num*/
-		SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
-			LITERAL_HASHSEQNUM, STRLEN(LITERAL_HASHSEQNUM), unique_seq_str, STRLEN(unique_seq_str), result);
+		uniq_ptr_len = STRLEN(uniq_ptr);
+		/* set ^#t("#TNAME",GVN,"#SEQNUM")++ */
+		SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+			LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM), uniq_ptr, uniq_ptr_len, result);
 		if (PUT_SUCCESS != result)
-		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 			return result;
-		}
 		/* set ^#t("#TNAME",GVN,"#TNCOUNT")++ */
-		BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
-			LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT));
+		BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+			LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT));
 		var_count = gvcst_get(val_ptr) ? mval2i(val_ptr) + 1 : 1;
 		i2mval(&val, var_count);
-		SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trigname_len,
-			LITERAL_HASHTNCOUNT, STRLEN(LITERAL_HASHTNCOUNT), val, result);
+		SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), trig_name, trigname_len,
+			LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT), val, result);
 		if (PUT_SUCCESS != result)
-		{
-			RESTORE_TRIGGER_REGION_INFO(save_currkey);
 			return result;
-		}
-	} else
-		*uniq_ptr = '\0';	/* user supplied name */
-	seq_ptr = user_trigname_str;
-	memcpy(seq_ptr, trig_name, trigname_len);
-	seq_ptr += trigname_len;
-	if (0 == user_trigname_len)
-	{	/* Autogenerated */
+		seq_ptr = user_trigname_str;
+		memcpy(seq_ptr, trig_name, trigname_len);
+		seq_ptr += trigname_len;
 		*seq_ptr++ = TRIGNAME_SEQ_DELIM;
-		memcpy(seq_ptr, unique_seq_str, STRLEN(unique_seq_str));
-		seq_ptr += STRLEN(unique_seq_str);
-	}
-	*seq_ptr = '\0';
+		memcpy(seq_ptr, uniq_ptr, uniq_ptr_len);
+		seq_ptr += uniq_ptr_len;
+		user_trigname_len = trigname_len + 1 + uniq_ptr_len;
+	} else
+		seq_ptr = user_trigname_str + user_trigname_len;
 	ptr1 = name_and_index;
 	memcpy(ptr1, trigvn, trigvn_len);
 	ptr1 += trigvn_len;
 	*ptr1++ = '\0';
 	MV_FORCE_STR(trigger_count);
 	memcpy(ptr1, trigger_count->str.addr, trigger_count->str.len);
-	SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), user_trigname_str, STRLEN(user_trigname_str),
+	SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME), user_trigname_str, user_trigname_len,
 		name_and_index, trigvn_len + 1 + trigger_count->str.len, result);
 	if (PUT_SUCCESS != result)
-	{
-		RESTORE_TRIGGER_REGION_INFO(save_currkey);
 		return result;
-	}
-	*seq_ptr++ = TRIGNAME_SEQ_DELIM;
+	*seq_ptr++ = TRIGNAME_SEQ_DELIM; /* all trigger names end with a hash mark, so append one */
 	*seq_ptr = '\0';
-	RESTORE_TRIGGER_REGION_INFO(save_currkey);
 	return SEQ_SUCCESS;
 }
 
@@ -1065,43 +1124,30 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 {
 	char			add_delete;
 	char			ans[2];
-	sgmnt_addrs		*csa;
-	boolean_t		cmd_modified;
 	char			db_trig_name[MAX_USER_TRIGNAME_LEN + 1];
-	boolean_t		full_match;
+	boolean_t		multiline_parse_fail;
 	mname_entry		gvname;
-	boolean_t		kill_cmp;
 	int4			max_len;
 	boolean_t 		multi_line, multi_line_xecute;
-	mval			mv_hash;
-	boolean_t		new_name;
-	int			num;
-	int4			offset;
-	char			*ptr1;
 	int4			rec_len;
 	int4			rec_num;
-	boolean_t		result;
-	gv_namehead		*save_gvtarget;
-	boolean_t		set_cmp;
-	boolean_t		skip_set_trigger;
 	boolean_t		status;
-	int			sub_indx;
 	char			tcount[MAX_DIGITS_IN_INT];
 	char			tfile_rec_val[MAX_BUFF_SIZE];
 	char			trig_cmds[MAX_COMMANDS_LEN + 1];
-	mval			*trig_cnt_ptr;
-	char			trig_name[MAX_USER_TRIGNAME_LEN + 2];	/* One spot for '#' delimiter and one for trailing '\0' */
 	char			trig_options[MAX_OPTIONS_LEN + 1];
 	char			trigvn[MAX_MIDENT_LEN + 1];
-	mval			trigger_count;
+	char			disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1];
+					/* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name,
+					 * 1 for ")" and 1 for trailing '\0'.
+					 */
+	int			disp_trigvn_len;
 	int			trigvn_len;
-	int			trigindx, kill_index = -1;
-	int4			updates = 0;
-	char			*values[NUM_SUBS];
-	uint4			value_len[NUM_SUBS];
+	char			*values[NUM_SUBS], *save_values[NUM_SUBS];
+	uint4			value_len[NUM_SUBS], save_value_len[NUM_SUBS];
 	stringkey		kill_trigger_hash, set_trigger_hash;
-	char			tmp_str[MAX_HASH_INDEX_LEN + 1 + MAX_DIGITS_IN_INT];
-	char			xecute_buffer[MAX_BUFF_SIZE + MAX_XECUTE_LEN];
+	char			tmp_str[MAX_HASH_LEN + 1];
+	char			xecute_buffer[MAX_BUFF_SIZE + MAX_XECUTE_LEN], dispbuff[MAX_TRIG_DISPLEN];
 	mval			xecute_index, xecute_size;
 	mval			reportname, reportnamealt;
 	mval			trigjrec;
@@ -1110,18 +1156,35 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 	io_pair			io_save_device;
 	int4			max_xecute_size;
 	boolean_t		no_error;
-	boolean_t		newtrigger;
 	gvnh_reg_t		*gvnh_reg;
+	char			utilprefix[1024];
+	int			utilprefixlen, displen;
+	int			reg_index, min_reg_index, max_reg_index;
+	boolean_t		first_gtmio;
+	boolean_t		jnl_format_done, new_name_check_done, new_name, first_error;
+	trig_stats_t		this_trig_status, overall_trig_status;
+	gv_namehead		*gvt;
+	gvnh_spanreg_t		*gvspan;
+	hash128_state_t		set_hash_state, kill_hash_state;
+	uint4			set_hash_totlen, kill_hash_totlen;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
+	/* We are going to operate on the ^#t global which does not span regions. Reset gd_targ_gvnh_reg
+	 * leftover from previous GV_BIND_SUBSNAME_IF_GVSPAN call to not affect any op_zprevious etc.
+	 * (e.g. invocation trigger_update_rec -> trigupdrec_reg -> add_trigger_hash_entry -> op_zprevious)
+	 * so it focuses on gvcst_zprevious instead of gvcst_spr_zprevious for the ^#t global.
+	 * It is okay not to restore TREF(gd_targ_gvnh_reg) since it will be initialized as part of the
+	 * next op_gv* call done by the caller (be it mumps or mupip).
+	 */
+	TREF(gd_targ_gvnh_reg) = NULL;
 	assert(dollar_tlevel);
 	assert(0 > memcmp(LITERAL_HASHLABEL, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHLABEL), STRLEN(LITERAL_MAXHASHVAL))));
 	assert(0 > memcmp(LITERAL_HASHCOUNT, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHCOUNT), STRLEN(LITERAL_MAXHASHVAL))));
 	assert(0 > memcmp(LITERAL_HASHCYCLE, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHCYCLE), STRLEN(LITERAL_MAXHASHVAL))));
 	assert(0 > memcmp(LITERAL_HASHTNAME, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHTNAME), STRLEN(LITERAL_MAXHASHVAL))));
 	assert(0 > memcmp(LITERAL_HASHTNCOUNT, LITERAL_MAXHASHVAL, MIN(STRLEN(LITERAL_HASHTNCOUNT), STRLEN(LITERAL_MAXHASHVAL))));
-	rec_num = ((NULL == record_num)? 0 : *record_num);
+	rec_num = (NULL == record_num) ? 0 : *record_num;
 	gvinit();
 	trigjrec.mvtype = MV_STR;
 	trigjrec.str.len = len;
@@ -1139,8 +1202,10 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 		return TRIG_SUCCESS;
 	if (('-' != *trigger_rec) && ('+' != *trigger_rec))
 	{
-		trig_stats[STATS_ERROR]++;
-		util_out_print_gtmio("missing +/- at start of line: !AD", FLUSH, len, trigger_rec);
+		trig_stats[STATS_ERROR_TRIGFILE]++;
+		displen = MAX_TRIG_DISPLEN;
+		format2disp(trigger_rec, len, dispbuff, &displen);	/* returns displayable string in "dispbuff" */
+		util_out_print_gtmio("Error : missing +/- at start of line: !AD", FLUSH, displen, dispbuff);
 		return TRIG_FAILURE;
 	}
 	add_delete = *trigger_rec++;
@@ -1151,8 +1216,8 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 		{
 			if ((NULL == trigfile_device) && (NULL != trigjrecptr))
 			{
-				util_out_print_gtmio("Newline not allowed in trigger name for delete operation", FLUSH);
-				trig_stats[STATS_ERROR]++;
+				util_out_print_gtmio("Error : Newline not allowed in trigger name for delete operation", FLUSH);
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
 			if (!noprompt)
@@ -1166,44 +1231,44 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 					return TRIG_SUCCESS;
 				}
 			}
-			trigger_delete_all(--trigger_rec, len + 1);
+			trigger_delete_all(--trigger_rec, len + 1, trig_stats);	/* updates trig_stats[] appropriately */
 			return TRIG_SUCCESS;
 		} else if ((0 == len) || ('^' != *trigger_rec))
 		{	/* if the length < 0 let trigger_delete_name respond with the error message */
 			if ((NULL == trigfile_device) && (NULL != trigjrecptr))
 			{
-				util_out_print_gtmio("Newline not allowed in trigger name for delete operation", FLUSH);
-				trig_stats[STATS_ERROR]++;
+				util_out_print_gtmio("Error : Newline not allowed in trigger name for delete operation", FLUSH);
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
-			if (TRIG_FAILURE == (status = trigger_delete_name(--trigger_rec, len + 1, trig_stats)))
-				trig_stats[STATS_ERROR]++;
+			status = trigger_delete_name(--trigger_rec, len + 1, trig_stats); /* updates trig_stats[] appropriately */
 			return status;
 		}
 	}
 	values[GVSUBS_SUB] = tfile_rec_val;	/* GVSUBS will be the first entry set so initialize it */
 	max_len = (int4)SIZEOF(tfile_rec_val);
 	multi_line_xecute = FALSE;
-	no_error = TRUE;
 	if (!trigger_parse(trigger_rec, len, trigvn, values, value_len, &max_len, &multi_line_xecute))
 	{
-		if (multi_line_xecute)
-			no_error = FALSE;
-		else
-		{
-			trig_stats[STATS_ERROR]++;
-			return TRIG_FAILURE;
-		}
+		trig_stats[STATS_ERROR_TRIGFILE]++;
+		return TRIG_FAILURE;
 	}
 	trigvn_len = STRLEN(trigvn);
-	set_trigger_hash.str.addr = tmp_str;
-	set_trigger_hash.str.len = SIZEOF(tmp_str);
+	set_trigger_hash.str.addr = &tmp_str[0];
+	set_trigger_hash.str.len = MAX_HASH_LEN;
 	build_set_cmp_str(trigvn, trigvn_len, values, value_len, &set_trigger_hash.str, multi_line_xecute);
-	COMPUTE_HASH_STR(&set_trigger_hash);
-	kill_trigger_hash.str.addr = tmp_str;
-	kill_trigger_hash.str.len = SIZEOF(tmp_str);
+	/* Note that we are going to compute the hash of the trigger string in bits and pieces.
+	 * So use the STR_PHASH* macros (the progressive variants), not the STR_HASH macros.
+	 */
+	STR_PHASH_INIT(set_hash_state, set_hash_totlen);
+	STR_PHASH_PROCESS(set_hash_state, set_hash_totlen, set_trigger_hash.str.addr, set_trigger_hash.str.len);
+	kill_trigger_hash.str.addr = &tmp_str[0];
+	kill_trigger_hash.str.len = MAX_HASH_LEN;
 	build_kill_cmp_str(trigvn, trigvn_len, values, value_len, &kill_trigger_hash.str, multi_line_xecute);
-	COMPUTE_HASH_STR(&kill_trigger_hash);
+	STR_PHASH_INIT(kill_hash_state, kill_hash_totlen);
+	STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, kill_trigger_hash.str.addr, kill_trigger_hash.str.len);
+	first_gtmio = TRUE;
+	utilprefixlen = ARRAYSIZE(utilprefix);
 	if (multi_line_xecute)
 	{
 		if (NULL != trigfile_device)
@@ -1225,28 +1290,81 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 			io_save_device = io_curr_device;
 			io_curr_device = *trigfile_device;
 			multi_line = multi_line_xecute;
-			while (multi_line && (0 <= (rec_len = file_input_get(&trigger_rec))))
+			/* We are in a multi-line trigger definition. Each trigger line should now correspond to an M source line.
+			 * The GT.M compiler does not accept any M source line > MAX_SRCLINE bytes. So issue error right away in
+			 * case source line is > MAX_SRCLINE. No point reading the full line and then issuing the error.
+			 * Note that MAX_SRCLINE also includes the newline at end of line hence the MAX_SRCLINE - 1 usage below.
+			 */
+			multiline_parse_fail = FALSE;
+			while (multi_line)
 			{
-				rec_num++;
+				rec_len = file_input_get(&trigger_rec, MAX_SRCLINE - 1);
+				if (!io_curr_device.in->dollar.x)
+					rec_num++;
+				if (0 > rec_len)
+				{
+					assert((FILE_INPUT_GET_LINE2LONG == rec_len) || (FILE_INPUT_GET_ERROR == rec_len));
+					if (FILE_INPUT_GET_ERROR == rec_len)
+						break;
+					do
+					{	/* Read the remainder of the long line in as many MAX_SRCLINE chunks as needed */
+						rec_len = file_input_get(&trigger_rec, MAX_SRCLINE - 1);
+						if (!io_curr_device.in->dollar.x)
+							rec_num++;
+						if (0 <= rec_len)
+							break;	/* reached end of line */
+						assert((FILE_INPUT_GET_LINE2LONG == rec_len) || (FILE_INPUT_GET_ERROR == rec_len));
+						if (FILE_INPUT_GET_ERROR == rec_len)
+							break;
+					} while (TRUE);
+					if (FILE_INPUT_GET_ERROR == rec_len)
+						break;
+					if (!multiline_parse_fail)
+					{
+						UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
+						util_out_print_gtmio("Error : Multi-line trigger -XECUTE exceeds maximum "
+									"M source line length of !UL", FLUSH, MAX_SRCLINE);
+						value_len[XECUTE_SUB] = 1;
+						values[XECUTE_SUB][0] = ' ';
+						max_xecute_size = SIZEOF(xecute_buffer);
+					}
+					multiline_parse_fail = TRUE;
+				}
 				io_curr_device = io_save_device;	/* In case we have to write an error message */
-				no_error &= trigger_parse(trigger_rec, (uint4)rec_len, trigvn, values, value_len,
-									&max_xecute_size, &multi_line);
+				no_error = trigger_parse(trigger_rec, (uint4)rec_len, trigvn, values, value_len,
+											&max_xecute_size, &multi_line);
 				io_curr_device = *trigfile_device;
+				if (!no_error)
+				{	/* An error occurred (e.g. Trigger definition too long etc.).
+					 * Consume remainder of multi-line trigger definition before moving on.
+					 * But before that replace XECUTE string constructed till now with a dummy one.
+					 */
+					assert(!multi_line);
+					multi_line = TRUE;
+					multiline_parse_fail = TRUE;
+				}
+				if (multiline_parse_fail)
+				{
+					value_len[XECUTE_SUB] = 1;
+					values[XECUTE_SUB][0] = ' ';
+					max_xecute_size = SIZEOF(xecute_buffer);
+				}
 			}
 			trigjrec.str.len = trigjreclen + value_len[XECUTE_SUB];
 			if (NULL != record_num)
 				*record_num = rec_num;
-			if (!no_error)
+			if (0 > rec_len)
 			{
+				assert(FILE_INPUT_GET_ERROR == rec_len);
 				io_curr_device = io_save_device;
-				trig_stats[STATS_ERROR]++;
+				util_out_print_gtmio("Error : Multi-line trigger -XECUTE is not properly terminated", FLUSH);
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
-			if (0 > rec_len)
-			{
+			if (multiline_parse_fail)
+			{	/* error message has already been issued */
 				io_curr_device = io_save_device;
-				util_out_print_gtmio("Multi-line trigger -XECUTE is not properly terminated", FLUSH);
-				trig_stats[STATS_ERROR]++;
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
 			io_curr_device = io_save_device;
@@ -1256,20 +1374,20 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 			value_len[XECUTE_SUB] = trigjrec.str.addr + trigjrec.str.len - (trigjrecptr + 1);
 			if ('\n' != values[XECUTE_SUB][value_len[XECUTE_SUB] - 1])
 			{
-				util_out_print_gtmio("Multi-line xecute in $ztrigger ITEM must end in newline", FLUSH);
-				trig_stats[STATS_ERROR]++;
+				util_out_print_gtmio("Error : Multi-line xecute in $ztrigger ITEM must end in newline", FLUSH);
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
 			if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], TRUE))
 			{
-				CONV_STR_AND_PRINT("Error parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
-				trig_stats[STATS_ERROR]++;
+				CONV_STR_AND_PRINT("Error : Parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
+				trig_stats[STATS_ERROR_TRIGFILE]++;
 				return TRIG_FAILURE;
 			}
 			/* trigjrec is already properly set up */
 		}
-		STR_HASH(values[XECUTE_SUB], value_len[XECUTE_SUB], set_trigger_hash.hash_code, set_trigger_hash.hash_code);
-		STR_HASH(values[XECUTE_SUB], value_len[XECUTE_SUB], kill_trigger_hash.hash_code, kill_trigger_hash.hash_code);
+		STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, values[XECUTE_SUB], value_len[XECUTE_SUB]);
+		STR_PHASH_PROCESS(set_hash_state, set_hash_totlen, values[XECUTE_SUB], value_len[XECUTE_SUB]);
 	} else if ((NULL == trigfile_device) && (NULL != trigjrecptr))
 	{	/* If this is a not a multi-line xecute string, we dont expect newlines. The only exception is if it is
 		 * the last byte in the string.
@@ -1277,324 +1395,557 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 		*trigjrecptr++;
 		if (trigjrecptr != (trigjrec.str.addr + trigjrec.str.len))
 		{
-			util_out_print_gtmio("Newline allowed only inside multi-line xecute in $ztrigger ITEM", FLUSH);
-			trig_stats[STATS_ERROR]++;
+			util_out_print_gtmio("Error : Newline allowed only inside multi-line xecute in $ztrigger ITEM", FLUSH);
+			trig_stats[STATS_ERROR_TRIGFILE]++;
 			return TRIG_FAILURE;
 		}
 	}
+	STR_PHASH_RESULT(set_hash_state, set_hash_totlen, set_trigger_hash.hash_code);
+	STR_PHASH_RESULT(kill_hash_state, kill_hash_totlen, kill_trigger_hash.hash_code);
 	gvname.var_name.addr = trigvn;
 	gvname.var_name.len = trigvn_len;
 	COMPUTE_HASH_MNAME(&gvname);
 	GV_BIND_NAME_ONLY(gd_header, &gvname, gvnh_reg);
-	/* Trigger updates are not currently supported for globals spanning multiple regions */
-	if (NULL != gvnh_reg->gvspan)
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNOSPANGBL, 2, trigvn_len, trigvn);
-	/* Now that we know this is not a spanning global, there is no need to do a GV_BIND_SUBSNAME* macro call.
-	 * gv_cur_region/gv_target already point to the correct region.
-	 */
+	gvspan = gvnh_reg->gvspan;
+	if (NULL != gvspan)
+	{
+		gvnh_spanreg_subs_gvt_init(gvnh_reg, gd_header, NULL);
+		reg_index = gvspan->min_reg_index;
+		min_reg_index = gvspan->min_reg_index;
+		max_reg_index = gvspan->max_reg_index;
+		assert(0 <= reg_index);
+		assert(reg_index < gd_header->n_regions);
+		gvt = GET_REAL_GVT(gvspan->gvt_array[reg_index - min_reg_index]);
+		assert(NULL != gvt);
+		gv_target = gvt;
+		gv_cur_region = gd_header->regions + reg_index;
+		change_reg();
+		SET_DISP_TRIGVN(gv_cur_region, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+		/* Save values[] and value_len[] arrays since they might be overwritten inside "trigupdrec_reg"
+		 * but we need the unmodified values for each call to that function.
+		 */
+		assert(SIZEOF(value_len) == SIZEOF(save_value_len));
+		memcpy(save_value_len, value_len, SIZEOF(value_len));
+		assert(SIZEOF(values) == SIZEOF(save_values));
+		memcpy(save_values, values, SIZEOF(values));
+	} else
+	{
+		memcpy(disp_trigvn, trigvn, trigvn_len);
+		disp_trigvn_len = trigvn_len;
+		disp_trigvn[disp_trigvn_len] = '\0';	/* null terminate just in case */
+	}
+	jnl_format_done = FALSE;
+	new_name_check_done = FALSE;
+	first_error = TRUE;
+	overall_trig_status = STATS_UNCHANGED_TRIGFILE;
+	do
+	{	/* At this point gv_cur_region/cs_addrs/gv_target already point to the correct region.
+		 * For a spanning global, they point to one of the spanned regions in each iteration of the do-while loop below.
+		 */
+		this_trig_status = trigupdrec_reg(trigvn, trigvn_len, &jnl_format_done, &trigjrec,
+						&new_name_check_done, &new_name, &values[0], &value_len[0], add_delete,
+						&kill_trigger_hash, &set_trigger_hash, &disp_trigvn[0], disp_trigvn_len, trig_stats,
+						&first_gtmio, utilprefix, &utilprefixlen);
+		assert((STATS_UNCHANGED_TRIGFILE == this_trig_status) || (STATS_NOERROR_TRIGFILE == this_trig_status)
+			|| (STATS_ERROR_TRIGFILE == this_trig_status));
+		if (STATS_ERROR_TRIGFILE == this_trig_status)
+		{
+			if (first_error)
+			{
+				trig_stats[STATS_ERROR_TRIGFILE]++;
+				first_error = FALSE;
+			}
+			overall_trig_status = STATS_ERROR_TRIGFILE;
+		} else if (STATS_UNCHANGED_TRIGFILE == overall_trig_status)
+			overall_trig_status = this_trig_status;
+		/* else if (STATS_NOERROR_TRIGFILE == overall_trig_status) : it is already what it should be */
+		/* else if (STATS_ERROR_TRIGFILE == overall_trig_status)   : it is already what it should be */
+		if (NULL == gvspan)
+			break;
+		if (reg_index >= max_reg_index)
+			break;
+		do
+		{
+			reg_index++;
+			assert(reg_index <= max_reg_index);
+			assert(reg_index < gd_header->n_regions);
+			gvt = GET_REAL_GVT(gvspan->gvt_array[reg_index - min_reg_index]);
+			if (NULL == gvt)
+			{
+				assert(reg_index < max_reg_index);
+				continue;
+			}
+			gv_target = gvt;
+			gv_cur_region = gd_header->regions + reg_index;
+			change_reg();
+			SET_DISP_TRIGVN(gv_cur_region, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
+			/* Restore values[] and value_len[] before next call to "trigupdrec_reg" */
+			assert(SIZEOF(value_len) == SIZEOF(save_value_len));
+			memcpy(value_len, save_value_len, SIZEOF(save_value_len));
+			assert(SIZEOF(values) == SIZEOF(save_values));
+			memcpy(values, save_values, SIZEOF(save_values));
+			break;
+		} while (TRUE);
+	} while (TRUE);
+	if ((STATS_UNCHANGED_TRIGFILE == overall_trig_status) || (STATS_NOERROR_TRIGFILE == overall_trig_status))
+	{
+		trig_stats[overall_trig_status]++;
+		return TRIG_SUCCESS;
+	} else
+	{
+		assert(STATS_ERROR_TRIGFILE == overall_trig_status);
+		return TRIG_FAILURE;
+	}
+}
+
+STATICFNDEF trig_stats_t trigupdrec_reg(char *trigvn, int trigvn_len, boolean_t *jnl_format_done, mval *trigjrec,
+	boolean_t *new_name_check_done, boolean_t *new_name_ptr, char **values, uint4 *value_len, char add_delete,
+	stringkey *kill_trigger_hash, stringkey *set_trigger_hash, char *disp_trigvn, int disp_trigvn_len, uint4 *trig_stats,
+	boolean_t *first_gtmio, char *utilprefix, int *utilprefixlen)
+{
+	mval			trigname[NUM_OPRS]; /* names of matching kill and/or set trigger */
+	boolean_t		new_name;
+	sgmnt_addrs		*csa;
+	mval			dummymval;
+	boolean_t		skip_set_trigger, trigger_exists;
+	mval			trigger_count;
+	boolean_t		newtrigger;
+	int			set_index, kill_index, tmp_index;
+	boolean_t		db_matched_kill, db_matched_set, tmp_matched_kill, tmp_matched_set;
+	boolean_t		full_match, new_match;
+	boolean_t		kill_cmp, set_cmp;
+	boolean_t		is_set;
+	int			oprtype, oprstart, oprend, set_kill_bitmask;
+	char			*oprname[] = { "Non-SET", "SET", "SET and/or Non-SET"};	/* index 0 corresponds to OPR_KILL,
+											 * 1 to OPR_SET,
+											 * 2 if OPR_SETKILL
+											 */
+	char			*opname;
+	int4			updates;
+	uint4			trigload_status;
+	mval			*trig_cnt_ptr;
+	int			num;
+	boolean_t		result;
+	int			sub_indx;
+	int4			max_len;
+	mval			xecute_index, xecute_size;
+	int4			offset;
+	char			*ptr1;
+	mval			mv_hash;
+	char			trig_name[MAX_USER_TRIGNAME_LEN + 2];	/* One spot for '#' delimiter and one for trailing '\0' */
+
+	csa = cs_addrs;
+	if (NULL == csa)	/* Remote region */
+		rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_REMOTEDBNOTRIG, 4, trigvn_len, trigvn, REG_LEN_STR(gv_cur_region));
 	if (gv_cur_region->read_only)
-		rts_error_csa(CSA_ARG(gv_target->gd_csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
+		rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
 	assert(cs_addrs == gv_target->gd_csa);
-	csa = cs_addrs;
-	/* Now that the gv_target of the global the trigger refers to is setup, check if we are attempting to modify/delete a
-	 * trigger for a global that has already had a trigger fire in this transaction. For these single-region (at a time)
-	 * checks, we can do them all the time as they are cheap.
-	 */
-	if (gv_target->trig_local_tn == local_tn)
-		rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_TRIGMODINTP);
 	csa->incr_db_trigger_cycle = TRUE; /* so that we increment csd->db_trigger_cycle at commit time */
 	if (dollar_ztrigger_invoked)
-	{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction, on this region, will re-read
-		 * triggers. Note that the below increment happens for every record added. So, even if a single trigger file loaded
-		 * multiple triggers on the same region, db_dztrigger_cycle will be incremented more than one for same transaction.
-		 * This is considered okay since we only need db_dztrigger_cycle to be equal to a different value than
-		 * gvt->db_dztrigger_cycle
+	{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction, on this region,
+		 * will re-read triggers. Note that the below increment happens for every record added. So, even if a
+		 * single trigger file loaded multiple triggers on the same region, db_dztrigger_cycle will be incremented
+		 * more than one for same transaction. This is considered okay since we only need db_dztrigger_cycle to
+		 * be equal to a different value than gvt->db_dztrigger_cycle.
 		 */
 		csa->db_dztrigger_cycle++;
 	}
-	if (JNL_WRITE_LOGICAL_RECS(csa))
-	{
-		assert(!gv_cur_region->read_only);
-		/* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in case this is a NO-OP
-		 * trigger operation that wont happen and we still want to write a TLGTRIG/ULGTRIG journal record. Hence
-		 * the need to do this.
+	if (!*jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
+	{	/* Attach to jnlpool if replication is turned on. Normally SET or KILL of the ^#t records take care of this
+		 * but in case this is a NO-OP trigger operation that wont happen and we still want to write a
+		 * TLGTRIG/ULGTRIG journal record. Hence the need to do this. Also write a LGTRIG record in just one region
+		 * in case this is a global spanning multiple regions.
 		 */
 		JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);
 		assert(dollar_tlevel);
 		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
 									 * even if NO db updates happen to ^#t nodes. */
-		jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+		jnl_format(JNL_LGTRIG, NULL, trigjrec, 0);
+		*jnl_format_done = TRUE;
 	}
 	SET_GVTARGET_TO_HASHT_GBL(csa);
 	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
-	new_name = check_unique_trigger_name(trigvn, trigvn_len, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
-	cmd_modified = skip_set_trigger = newtrigger = FALSE;
-	trigindx = 1;
+	if (csa->hdr->hasht_upgrade_needed)
+	{	/* ^#t needs to be upgraded first before reading/updating it. Cannot proceed. */
+		if (0 == gv_target->root)
+		{
+			csa->hdr->hasht_upgrade_needed = FALSE;	/* Reset now that we know there is no ^#t global in this db.
+								 * Note: It is safe to do so even if we dont hold crit.
+								 */
+		} else
+			rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEEDTRIGUPGRD, 2, DB_LEN_STR(gv_cur_region));
+	}
+	if (!*new_name_check_done)
+	{	/* Make sure below call is done only ONCE for a global spanning multiple regions since this call goes
+		 * through all regions in the gld to figure out if a user-defined trigger name is unique.
+		 */
+		new_name = check_unique_trigger_name_full(values, value_len, &dummymval, &new_match,
+						trigvn, trigvn_len, set_trigger_hash, kill_trigger_hash);
+		*new_name_ptr = new_name;
+		*new_name_check_done = TRUE;
+	} else
+		new_name = *new_name_ptr;
+	skip_set_trigger = FALSE;
 	assert(('+' == add_delete) || ('-' == add_delete));	/* Has to be + or - */
-	if (0 != gv_target->root)
+	if (gv_target->root)
 	{
 		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
 		if (gvcst_get(&trigger_count))
 		{
-			if (trigger_already_exists(trigvn, trigvn_len, values, value_len, &trigindx, &kill_index, &set_cmp,
-						   &kill_cmp, &full_match, &set_trigger_hash, &kill_trigger_hash,
-						   &reportname, &reportnamealt))
+			trigger_exists = trigger_already_exists(trigvn, trigvn_len, values, value_len,
+							set_trigger_hash, kill_trigger_hash,
+							&set_index, &kill_index,
+							&db_matched_set, &db_matched_kill, &full_match,
+							&trigname[OPR_SET], &trigname[OPR_KILL]);
+			newtrigger = FALSE;
+		} else
+		{
+			newtrigger = TRUE;
+			trigger_exists = FALSE;
+		}
+	} else
+	{
+		newtrigger = TRUE;
+		trigger_exists = FALSE;
+	}
+	set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
+	kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
+	updates = 0;
+	trigload_status = STATS_UNCHANGED_TRIGFILE;
+	if (trigger_exists)
+	{
+		if ((-1 != kill_index) && (set_index || set_cmp) && value_len[TRIGNAME_SUB])
+		{	/* Cannot match two different triggers (corresponding to "kill_index" and "set_index")
+			 * with the same user defined name. Note that it is possible if set_index==0 that the
+			 * set type trigger does not exist yet but will be created by this call to trigger_update_rec.
+			 * Treat that case too as if the separate set trigger existed.
+			 */
+			UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+			if (set_index)
+				util_out_print_gtmio("Error : Input trigger on ^!AD with trigger name !AD"		\
+				       " cannot match two different triggers named !AD and !AD at the same time",
+				       FLUSH, disp_trigvn_len, disp_trigvn,
+				       value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+				       trigname[OPR_KILL].str.len, trigname[OPR_KILL].str.addr,
+				       trigname[OPR_SET].str.len, trigname[OPR_SET].str.addr);
+			else
+				util_out_print_gtmio("Error : Input trigger on ^!AD with trigger name !AD"	\
+				       " cannot match a trigger named !AD and a to-be-created SET trigger"	\
+				       " at the same time", FLUSH, disp_trigvn_len, disp_trigvn,
+				       value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+				       trigname[OPR_KILL].str.len, trigname[OPR_KILL].str.addr);
+			return STATS_ERROR_TRIGFILE;
+		}
+		assert(new_name || !new_match || full_match);
+		if (!new_name && ('+' == add_delete) && !full_match)
+		{
+			opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+			TRIGGER_SAME_NAME_EXISTS_ERROR(opname, disp_trigvn_len, disp_trigvn);
+		}
+		oprstart = (-1 != kill_index) ? OPR_KILL : (OPR_KILL + 1);
+		oprend = (0 != set_index) ? (OPR_SET + 1) : OPR_SET;
+		assert(NUM_OPRS == (OPR_SET + 1));
+		assert(ARRAYSIZE(oprname) == (OPR_SET + 2));
+		set_kill_bitmask = OPR_SETKILL;
+		for (oprtype = oprstart; oprtype < oprend; oprtype++)
+		{
+			assert((OPR_KILL == oprtype) || (OPR_SET == oprtype));
+			if (OPR_KILL == oprtype)
+			{
+				tmp_matched_set = FALSE;
+				tmp_matched_kill = TRUE;
+				tmp_index = kill_index;
+				is_set = FALSE;
+				if (0 != set_index)
+				{	/* SET & KILL triggers are separate. This is the KILL trigger only invocation */
+					assert(set_cmp);
+					assert(kill_cmp);
+					set_kill_bitmask = OPR_KILL;
+				}
+				opname = oprname[OPR_KILL];
+			} else
+			{
+				tmp_matched_set = db_matched_set;
+				tmp_matched_kill = db_matched_kill;
+				tmp_index = set_index;
+				is_set = TRUE;
+				if (OPR_KILL == oprstart)
+				{
+					assert(set_cmp);
+					assert(kill_cmp);
+					set_kill_bitmask = OPR_SET;
+				}
+				opname = oprname[OPR_SET];
+			}
+			updates = modify_record(trigvn, trigvn_len, add_delete, tmp_index, values, value_len,
+					&trigger_count, tmp_matched_set, tmp_matched_kill,
+					kill_trigger_hash, set_trigger_hash, set_kill_bitmask);
+			if (0 > updates)
 			{
-				if (!new_name && ('+' == add_delete) && (!full_match))
+				switch (updates)
 				{
-					TRIGGER_SAME_NAME_EXISTS_ERROR;
+				case INVALID_LABEL:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : Current trigger format not compatible to update " \
+					       "the trigger on ^!AD named !AD", FLUSH, disp_trigvn_len, disp_trigvn,
+					       trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					return STATS_ERROR_TRIGFILE;
+				case KEY_TOO_LONG:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : ^!AD trigger - key larger than max key size", FLUSH,
+						disp_trigvn_len, disp_trigvn);
+					return STATS_ERROR_TRIGFILE;
+				case VAL_TOO_LONG:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : ^!AD trigger - value larger than record size", FLUSH,
+						disp_trigvn_len, disp_trigvn);
+					return STATS_ERROR_TRIGFILE;
+				case K_ZTK_CONFLICT:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : Command options !AD incompatible with trigger on " \
+						"^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
+						disp_trigvn_len, disp_trigvn,
+						trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					return STATS_ERROR_TRIGFILE;
+				case ADD_SET_NOCHNG_KILL_TRIG:
+					assert(!is_set);
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("!AZ trigger on ^!AD already present in trigger named !AD" \
+								" - no action taken", FLUSH, opname,
+								disp_trigvn_len, disp_trigvn,
+								trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					/* kill trigger is unchanged but set trigger (if present in a different trigger)
+					 * needs to be processed separately.
+					 */
+					break;
+				case ADD_SET_MODIFY_KILL_TRIG:
+					assert(!is_set);
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Modified !AZ trigger on ^!AD named !AD",
+							FLUSH, opname, disp_trigvn_len, disp_trigvn,
+							trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					trig_stats[STATS_MODIFIED]++;
+					trigload_status = STATS_NOERROR_TRIGFILE;
+					break;
+				case OPTIONS_CMDS_CONFLICT:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : Specified options and commands cannot both be different" \
+						" from those in trigger on ^!AD named !AD", FLUSH, disp_trigvn_len, disp_trigvn,
+							trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					return STATS_ERROR_TRIGFILE;
+				case NAME_CMDS_CONFLICT:
+					UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+					util_out_print_gtmio("Error : Specified name !AD different from that of trigger" \
+						" on ^!AD named !AD but specified commands do not contain those in trigger",
+							FLUSH, value_len[TRIGNAME_SUB], values[TRIGNAME_SUB],
+							disp_trigvn_len, disp_trigvn,
+							trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					return STATS_ERROR_TRIGFILE;
+				default:
+					assertpro(FALSE && updates);
+					break;
 				}
-				if (-1 != kill_index)
+			} else
+			{
+				skip_set_trigger = is_set;
+				if ((updates & (ADD_UPDATE_NAME | ADD_UPDATE_CMDS | ADD_UPDATE_OPTIONS))
+					|| (updates & (SUB_UPDATE_NAME | SUB_UPDATE_CMDS)))
 				{
-					if (0 != value_len[TRIGNAME_SUB])
-					{ /* can't match two different trigger with a user defined name */
-						trig_stats[STATS_ERROR]++;
-						util_out_print_gtmio("Conflicting trigger definition for global ^!AD. Definition " \
-						       "matches trigger named !AD and attempts to create a new trigger named !AD",
-						       FLUSH, trigvn_len, trigvn, reportnamealt.str.len, reportnamealt.str.addr,
-						       value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
-						return TRIG_FAILURE;
+					trig_stats[STATS_MODIFIED]++;
+					trigload_status = STATS_NOERROR_TRIGFILE;
+					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+					{
+						if (-1 == kill_index)
+							opname = (!set_cmp ? oprname[OPR_KILL]
+									: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+						UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+						util_out_print_gtmio("Modified !AZ trigger on ^!AD named !AD", FLUSH,
+									opname, disp_trigvn_len, disp_trigvn,
+									trigname[oprtype].str.len, trigname[oprtype].str.addr);
 					}
-					updates = modify_record(trigvn, trigvn_len, add_delete, kill_index, values, value_len,
-						&trigger_count, FALSE, TRUE, &kill_trigger_hash, &set_trigger_hash);
-					switch (updates)
+				} else if (updates & DELETE_REC)
+				{
+					trig_stats[STATS_DELETED]++;
+					trigload_status = STATS_NOERROR_TRIGFILE;
+					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
 					{
-						case INVALID_LABEL:
-							trig_stats[STATS_ERROR]++;
-							util_out_print_gtmio("Current trigger format not compatible to update " \
-							       "the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
-							       reportnamealt.str.len, reportnamealt.str.addr);
-							return TRIG_FAILURE;
-						case VAL_TOO_LONG:
-							trig_stats[STATS_ERROR]++;
-							util_out_print_gtmio("^!AD trigger - value larger than record size", FLUSH,
-								trigvn_len, trigvn);
-							return TRIG_FAILURE;
-						case K_ZTK_CONFLICT:
-							trig_stats[STATS_ERROR]++;
-							util_out_print_gtmio("Command options !AD incompatible with trigger on " \
-								"^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
-								trigvn_len, trigvn, reportnamealt.str.len, reportnamealt.str.addr);
-							return TRIG_FAILURE;
-						default:
-							if ((0 != (updates & ADD_UPDATE_CMDS)) ||
-							    (0 != (updates & SUB_UPDATE_CMDS)))
-							{
-								if (0 == trig_stats[STATS_ERROR])
-									util_out_print_gtmio("Updated trigger on ^!AD named " \
-											     "!AD and ", NOFLUSH, trigvn_len,
-											     trigvn, reportnamealt.str.len,
-											     reportnamealt.str.addr);
-								trig_stats[STATS_MODIFIED]++;
-							} else if ((0 != (updates & ADD_UPDATE_NAME)) ||
-								   (0 != (updates & SUB_UPDATE_NAME)) ||
-								   (0 != (updates & SUB_UPDATE_OPTIONS)) ||
-								   (0 != (updates & ADD_UPDATE_OPTIONS)))
-							{ /* NAME and OPTIONS cannot change on K-type match */
-								assertpro(FALSE);
-							} else if (0 != (updates & DELETE_REC))
-							{
-								if (0 == trig_stats[STATS_ERROR])
-									util_out_print_gtmio("Deleted trigger on ^!AD named "\
-											     "!AD and ", NOFLUSH, trigvn_len,
-											     trigvn, reportnamealt.str.len,
-											     reportnamealt.str.addr);
-								trig_stats[STATS_DELETED]++;
-								/* if trigger deleted, search for possible new SET trigger index */
-								if(kill_index < trigindx &&
-								   !(trigger_already_exists(trigvn, trigvn_len, values, value_len,
-											    &trigindx, &kill_index,
-											    &set_cmp, &kill_cmp, &full_match,
-											    &set_trigger_hash, &kill_trigger_hash,
-											    &reportname, &reportnamealt)))
-								{ /* SET trigger found previously is not found again */
-									if (CDB_STAGNATE > t_tries)
-										t_retry(cdb_sc_triggermod);
-									else
-									{
-										assert(WBTEST_HELPOUT_TRIGDEFBAD == \
-												gtm_white_box_test_case_number);
-										trig_stats[STATS_ERROR]++;
-										util_out_print_gtmio("Previously found trigger on" \
-												     "^!AD ,named !AD but cannot " \
-												     "find it again",
-												     FLUSH, trigvn_len, trigvn,
-												     reportnamealt.str.len,
-												     reportnamealt.str.addr);
-									}
-									return TRIG_FAILURE;
-								}
-							} else
-							{
-								util_out_print_gtmio("Trigger on ^!AD already present " \
-										     "-- same as trigger named !AD and ",
-										     NOFLUSH, trigvn_len, trigvn,
-										     reportname.str.len, reportname.str.addr);
-								trig_stats[STATS_UNCHANGED]++;
-							}
+						if (-1 == kill_index)
+							opname = (!set_cmp ? oprname[OPR_KILL]
+									: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+						UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+						util_out_print_gtmio("Deleted !AZ trigger on ^!AD named !AD",
+									FLUSH, opname, disp_trigvn_len, disp_trigvn,
+									trigname[oprtype].str.len, trigname[oprtype].str.addr);
 					}
-				}
-				updates = modify_record(trigvn, trigvn_len, add_delete, trigindx, values, value_len,
-						&trigger_count, set_cmp, kill_cmp, &kill_trigger_hash, &set_trigger_hash);
-				switch (updates)
+					/* if KILL trigger deleted, search for possible new SET trigger index */
+					if (!is_set && (kill_index < set_index)
+						&& !(trigger_already_exists(trigvn, trigvn_len, values, value_len,
+								set_trigger_hash, kill_trigger_hash, &set_index,
+								&tmp_index, &db_matched_set, &db_matched_kill,
+								&full_match, &trigname[oprtype], &trigname[oprtype])))
+					{	/* SET trigger found previously is not found again */
+						if (CDB_STAGNATE > t_tries)
+							t_retry(cdb_sc_triggermod);
+						assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
+						util_out_print_gtmio("Error : Previously found SET trigger " \
+							"on ^!AD, named !AD but cannot find it again",
+							FLUSH, disp_trigvn_len, disp_trigvn,
+							trigname[oprtype].str.len, trigname[oprtype].str.addr);
+						return STATS_ERROR_TRIGFILE;
+					}
+				} else if ('+' == add_delete)
 				{
-					case ADD_NEW_TRIGGER:
-						if (0 != value_len[TRIGNAME_SUB])
-						{ /* can't add a new trigger when you already matched on a name */
-							trig_stats[STATS_ERROR]++;
-							util_out_print_gtmio("Conflicting trigger definition for global ^!AD." \
-									     " Definition matches trigger named !AD and attempts" \
-									     " to create a new trigger named !AD", FLUSH,
-									     trigvn_len, trigvn,
-									     reportname.str.len, reportname.str.addr,
-									     value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
-							return TRIG_FAILURE;
-						}
-						cmd_modified = TRUE;
-						trig_cnt_ptr = &trigger_count;
-						num = mval2i(trig_cnt_ptr);
-						trigindx = ++num;
-						i2mval(&trigger_count, num);
-						break;
-					case INVALID_LABEL:
-						trig_stats[STATS_ERROR]++;
-						util_out_print_gtmio("Current trigger format not compatible to update " \
-						       "the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
-						       reportname.str.len, reportname.str.addr);
-						return TRIG_FAILURE;
-					case VAL_TOO_LONG:
-						trig_stats[STATS_ERROR]++;
-						util_out_print_gtmio("^!AD trigger - value larger than record size", FLUSH,
-							trigvn_len, trigvn);
-						return TRIG_FAILURE;
-					case K_ZTK_CONFLICT:
-						trig_stats[STATS_ERROR]++;
-						util_out_print_gtmio("Command options !AD incompatible with trigger on " \
-							"^!AD named !AD", FLUSH, value_len[CMD_SUB], values[CMD_SUB],
-							trigvn_len, trigvn, reportname.str.len, reportname.str.addr);
-						return TRIG_FAILURE;
-					default:
-						skip_set_trigger = TRUE;
-						if ((0 != (updates & ADD_UPDATE_NAME)) || (0 != (updates & ADD_UPDATE_CMDS))
-							|| (0 != (updates & ADD_UPDATE_OPTIONS)))
-						{
-							i2mval(&trigger_count, trigindx);
-							trig_stats[STATS_MODIFIED]++;
-							if (0 == trig_stats[STATS_ERROR])
-								util_out_print_gtmio("Updated trigger on ^!AD named !AD", FLUSH,
-										     trigvn_len, trigvn, reportname.str.len,
-										     reportname.str.addr);
-						} else if (0 != (updates & DELETE_REC))
-						{
-							trig_stats[STATS_DELETED]++;
-							if (0 == trig_stats[STATS_ERROR])
-								util_out_print_gtmio("Deleted trigger on ^!AD named !AD",
-										     FLUSH, trigvn_len, trigvn,
-										     reportname.str.len, reportname.str.addr);
-						} else if ((0 != (updates & SUB_UPDATE_NAME)) || (0 != (updates & SUB_UPDATE_CMDS))
-							   || (0 != (updates & SUB_UPDATE_OPTIONS)))
-						{
-							trig_stats[STATS_MODIFIED]++;
-							if (0 == trig_stats[STATS_ERROR])
-								util_out_print_gtmio("Updated trigger on ^!AD named !AD", FLUSH,
-										     trigvn_len, trigvn, reportname.str.len,
-										     reportname.str.addr);
-						} else if ('+' == add_delete)
-						{
-							if (0 == trig_stats[STATS_ERROR])
-							{
-								util_out_print_gtmio("Trigger on ^!AD already present -- same" \
-									" as trigger named !AD", FLUSH, trigvn_len, trigvn,
-									reportname.str.len, reportname.str.addr);
-								trig_stats[STATS_UNCHANGED]++;
-							}
+					assert(0 == updates);
+					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+					{
+						if (-1 == kill_index)
+							opname = (!set_cmp ? oprname[OPR_KILL]
+									: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+						UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+						util_out_print_gtmio("!AZ trigger on ^!AD already present " \
+							"in trigger named !AD - no action taken",
+							FLUSH, opname, disp_trigvn_len, disp_trigvn,
+							trigname[oprtype].str.len, trigname[oprtype].str.addr);
+					}
+				} else
+				{
+					assert(0 == updates);
+					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+					{
+						if (-1 == kill_index)
+							opname = (!set_cmp ? oprname[OPR_KILL]
+									: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+						UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+						if (!value_len[TRIGNAME_SUB]
+							|| ((trigname[oprtype].str.len == value_len[TRIGNAME_SUB])
+								&& !memcmp(values[TRIGNAME_SUB], trigname[oprtype].str.addr,
+									value_len[TRIGNAME_SUB])))
+						{	/* Trigger name matches input name or name was not specified (in which
+							 * case name is considered to match). So the command specified
+							 * does not exist for deletion.
+							 */
+							util_out_print_gtmio("!AZ trigger on ^!AD not present in trigger "	\
+								"named !AD - no action taken", FLUSH, opname,
+								disp_trigvn_len, disp_trigvn,
+								trigname[oprtype].str.len, trigname[oprtype].str.addr);
 						} else
 						{
-							if (0 == trig_stats[STATS_ERROR])
-							{
-								util_out_print_gtmio("Trigger on ^!AD does not exist - " \
-									"no action taken", FLUSH, trigvn_len, trigvn);
-								trig_stats[STATS_UNCHANGED]++;
-							}
+							util_out_print_gtmio("!AZ trigger on ^!AD matches trigger "	\
+								"named !AD but not with specified name !AD "		\
+								"- no action taken", FLUSH, opname,
+								disp_trigvn_len, disp_trigvn,
+								trigname[oprtype].str.len, trigname[oprtype].str.addr,
+								value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
 						}
+					}
 				}
-			} else if ('+' == add_delete)
-			{
-				assert(0 == trigindx);
-				if (!new_name)
-				{
-					TRIGGER_SAME_NAME_EXISTS_ERROR;
-				}
-				trig_cnt_ptr = &trigger_count;
-				num = mval2i(trig_cnt_ptr);
-				trigindx = ++num;
-				i2mval(&trigger_count, num);
-			} else
-			{ /* '-' == add_delete */
-				if (0 == trig_stats[STATS_ERROR])
-				{
-					trig_stats[STATS_UNCHANGED]++;
-					util_out_print_gtmio("Trigger on ^!AD does not exist - no action taken", FLUSH,
-							     trigvn_len, trigvn);
-				}
-				skip_set_trigger = TRUE;
 			}
-		} else
-			newtrigger = TRUE;
-	} else
-		newtrigger = TRUE;
-	if (newtrigger)
+		}
+		if (0 == set_index)
+		{
+			if (set_cmp)
+			{	/* SET was specified in the CMD list but no trigger was found, so treat this
+				 * as a trigger not existing case for both '+' and '-' cases of add_delete.
+				 */
+				trigger_exists = FALSE;
+				assert(!newtrigger);
+			} else if (-1 != kill_index)
+				skip_set_trigger = TRUE;
+		}
+	}
+	if (newtrigger || !trigger_exists)
 	{
 		if ('-' == add_delete)
 		{
-			if (0 == trig_stats[STATS_ERROR])
-				util_out_print_gtmio("Trigger on ^!AD does not exist - no action taken",
-						     FLUSH, trigvn_len, trigvn);
-			else
-				trig_stats[STATS_DELETED]++;
+			if (0 == trig_stats[STATS_ERROR_TRIGFILE])
+			{
+				if (newtrigger)
+					opname = (!set_cmp ? oprname[OPR_KILL]
+								: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+				else if (-1 == kill_index)
+					opname = (!set_cmp ? oprname[OPR_KILL]
+								: (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+				else
+					opname = oprname[OPR_SET];
+				UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+				/* At this point SET or KILL or both triggers specified might not exist hence the "and/or" */
+				util_out_print_gtmio("!AZ trigger on ^!AD does not exist - no action taken",
+						     FLUSH, opname, disp_trigvn_len, disp_trigvn);
+			}
 			skip_set_trigger = TRUE;
 		} else
 		{
-			if (!new_name)
+			if (!new_name && !new_match)
 			{
-				TRIGGER_SAME_NAME_EXISTS_ERROR;
+				opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+				TRIGGER_SAME_NAME_EXISTS_ERROR(opname, disp_trigvn_len, disp_trigvn);
+			}
+			if (newtrigger)
+			{
+				trigger_count = literal_one;
+				set_index = 1;
+			} else
+			{
+				assert(!trigger_exists);
+				assert(0 == set_index);
+				trig_cnt_ptr = &trigger_count;
+				num = mval2i(trig_cnt_ptr);
+				set_index = ++num;
+				i2mval(&trigger_count, num);
 			}
-			trigger_count = literal_one;
 		}
 	}
 	/* Since a specified trigger name will grow by 1, copy it to a long enough array */
-	if (((0 != (updates & ADD_UPDATE_NAME)) && ('-' != add_delete)) || !skip_set_trigger)
+	if (((updates & ADD_UPDATE_NAME) && ('+' == add_delete)) || !skip_set_trigger)
 	{
 		memcpy(trig_name, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB] + 1);
 		values[TRIGNAME_SUB] = trig_name;
-		result = gen_trigname_sequence(trigvn, trigvn_len, &trigger_count, values[TRIGNAME_SUB],
-					       value_len[TRIGNAME_SUB]);
+		result = gen_trigname_sequence(trigvn, trigvn_len, &trigger_count, values[TRIGNAME_SUB], value_len[TRIGNAME_SUB]);
 		if (SEQ_SUCCESS != result)
 		{
 			if (TOO_MANY_TRIGGERS == result)
-				util_out_print_gtmio("^!AD trigger - Too many triggers", FLUSH, trigvn_len, trigvn);
-			else
+			{
+				UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+				util_out_print_gtmio("Error : ^!AD trigger - Too many triggers", FLUSH,
+					disp_trigvn_len, disp_trigvn);
+			} else
 			{
 				TOO_LONG_REC_KEY_ERROR_MSG;
 			}
-			trig_stats[STATS_ERROR]++;
-			return TRIG_FAILURE;
+			return STATS_ERROR_TRIGFILE;
 		}
 	}
-	if (!skip_set_trigger && (0 == trig_stats[STATS_ERROR]))
+	if (trig_stats[STATS_ERROR_TRIGFILE])
+	{
+		if ('+' == add_delete)
+		{
+			trig_stats[STATS_ADDED]++;
+			trigload_status = STATS_NOERROR_TRIGFILE;
+		}
+		UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+		util_out_print_gtmio("No errors processing trigger for global ^!AD", FLUSH, disp_trigvn_len, disp_trigvn);
+	} else if (!skip_set_trigger)
 	{
+		if (!newtrigger && (-1 != kill_index))
+		{	/* KILL commands were separately processed in KILL trigger. So consider only SET as being specified */
+			value_len[CMD_SUB] = 1;
+			values[CMD_SUB][1] = '\0';
+			assert('S' == values[CMD_SUB][0]);
+		}
 		value_len[TRIGNAME_SUB] = STRLEN(values[TRIGNAME_SUB]);
 		values[CHSET_SUB] = (gtm_utf8_mode) ? UTF8_NAME : LITERAL_M;
 		value_len[CHSET_SUB] = STRLEN(values[CHSET_SUB]);
-		/* set ^#t(GVN,"#LABEL") = "2" */
+		/* set ^#t(GVN,"#LABEL") = "3" */
 		SET_TRIGGER_GLOBAL_SUB_SUB_STR(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL),
 					       HASHT_GBL_CURLABEL, STRLEN(HASHT_GBL_CURLABEL), result);
 		IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
-		trigger_incr_cycle(trigvn, trigvn_len);
 		/* set ^#t(GVN,"#COUNT") = trigger_count */
 		SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT),
 						trigger_count, result);
 		IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
+		/* Assert that BHASH and LHASH are not part of NUM_SUBS calculation (confirms the -2 done in #define of NUM_SUBS) */
+		assert(BHASH_SUB == NUM_SUBS);
+		assert(LHASH_SUB == (NUM_SUBS + 1));
 		for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
 		{
 			if (0 >= value_len[sub_indx])	/* subscript index length is zero (no longer used), skip it */
@@ -1628,8 +1979,7 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 						i2mval(&xecute_index, ++num);
 						BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, trigger_count,
 							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index);
-						offset = MIN(gv_cur_region->max_rec_size - (gv_currkey->end + 1 + SIZEOF(rec_hdr)),
-							     max_len);
+						offset = MIN(gv_cur_region->max_rec_size, max_len);
 						/* set ^#t(GVN,trigger_count,"XECUTE",num) = xecute string[offset] */
 						SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_STR(trigvn, trigvn_len, trigger_count,
 							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index,
@@ -1641,31 +1991,31 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
 				}
 			}
 		}
-		result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], trigindx, TRUE, &kill_trigger_hash,
-				&set_trigger_hash);
+		result = add_trigger_hash_entry(trigvn, trigvn_len, values[CMD_SUB], set_index, TRUE, kill_trigger_hash,
+				set_trigger_hash);
 		IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
-		MV_FORCE_UMVAL(&mv_hash, kill_trigger_hash.hash_code);
+		MV_FORCE_UMVAL(&mv_hash, kill_trigger_hash->hash_code);
 		SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_count,
 			trigger_subs[LHASH_SUB], STRLEN(trigger_subs[LHASH_SUB]), mv_hash, result);
 		IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
-		MV_FORCE_UMVAL(&mv_hash, set_trigger_hash.hash_code);
+		MV_FORCE_UMVAL(&mv_hash, set_trigger_hash->hash_code);
 		SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_count, trigger_subs[BHASH_SUB],
 			STRLEN(trigger_subs[BHASH_SUB]), mv_hash, result);
 		IF_ERROR_THEN_TOO_LONG_ERROR_MSG_AND_RETURN_FAILURE(result);
+		trigload_status = STATS_NOERROR_TRIGFILE;
 		trig_stats[STATS_ADDED]++;
-		if (cmd_modified)
-			util_out_print_gtmio("Modified commands of the trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
-					     value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
-		else
-			util_out_print_gtmio("Added trigger on ^!AD named !AD", FLUSH, trigvn_len, trigvn,
-					     value_len[TRIGNAME_SUB], values[TRIGNAME_SUB]);
-	} else if (0 != trig_stats[STATS_ERROR])
-	{
-		if ('+' == add_delete)
-			trig_stats[STATS_ADDED]++;
-		util_out_print_gtmio("No errors", FLUSH);
+		UTIL_PRINT_PREFIX_IF_NEEDED(*first_gtmio, utilprefix, utilprefixlen);
+		/* Recompute set_cmp and kill_cmp in case values[CMD_SUB] was modified above */
+		set_cmp = (NULL != strchr(values[CMD_SUB], 'S'));
+		kill_cmp = ((NULL != strchr(values[CMD_SUB], 'K')) || (NULL != strchr(values[CMD_SUB], 'R')));
+		opname = (!set_cmp ? oprname[OPR_KILL] : (!kill_cmp ? oprname[OPR_SET] : oprname[OPR_SETKILL]));
+		util_out_print_gtmio("Added !AZ trigger on ^!AD named !AD", FLUSH, opname, disp_trigvn_len, disp_trigvn,
+				     value_len[TRIGNAME_SUB] - 1, values[TRIGNAME_SUB]); /* -1 to remove # from tail of name */
 	}
-	return TRIG_SUCCESS;
+	assert((STATS_UNCHANGED_TRIGFILE == trigload_status) || (STATS_NOERROR_TRIGFILE == trigload_status));
+	if ((0 == trig_stats[STATS_ERROR_TRIGFILE]) && (STATS_NOERROR_TRIGFILE == trigload_status))
+		trigger_incr_cycle(trigvn, trigvn_len);	/* ^#t records changed in this function, increment cycle */
+	return trigload_status;
 }
 
 STATICFNDEF boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats)
@@ -1686,6 +2036,8 @@ STATICFNDEF boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, bo
 	{	/* Record cannot be committed - undo everything */
 		assert(donot_INVOKE_MUMTSTART);
 		DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE);
+		/* Print $ztrigger/mupip-trigger output before rolling back TP */
+		TP_ZTRIGBUFF_PRINT;
 		OP_TROLLBACK(-1);		/* returns but kills implicit transaction */
 	}
 	REVERT;
@@ -1718,7 +2070,7 @@ boolean_t trigger_update(char *trigger_rec, uint4 len)
 		 * below after a successful op_tcommit of the $ZTRIGGER operation. We cannot check that dollar_tlevel is zero
 		 * since the op_tstart done below can be a nested sub-transaction
 		 */
-		op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
+		op_tstart(IMPLICIT_TSTART, TRUE, &ts_mv, 0); /* 0 ==> save no locals but RESTART OK */
 		/* The following for loop structure is similar to that in module trigger_trgfile.c (function
 		 * "trigger_trgfile_tpwrap") and module gv_trigger.c (function gvtr_db_tpwrap) so any changes here
 		 * might need to be reflected there as well.
@@ -1743,8 +2095,6 @@ boolean_t trigger_update(char *trigger_rec, uint4 len)
 			 * trigger load logic already takes care of doing INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED before doing the
 			 * actual trigger load
 			 */
-			util_out_print_gtmio("RESTART has invalidated this transaction's previous output.  New output follows.",
-					     FLUSH);
 			/* We expect the above function to return with either op_tcommit or a tp_restart invoked.
 			 * In the case of op_tcommit, we expect dollar_tlevel to be 0 and if so we break out of the loop.
 			 * In the tp_restart case, we expect a maximum of 4 tries/retries and much lesser usually.
diff --git a/sr_unix/trigger_update_protos.h b/sr_unix/trigger_update_protos.h
index d312ad6..a6a6c58 100644
--- a/sr_unix/trigger_update_protos.h
+++ b/sr_unix/trigger_update_protos.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2010, 2011 Fidelity Information Services, Inc	*
+ *	Copyright 2010, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -12,34 +12,41 @@
 #ifndef TRIGGER_UPDATE_PROTOS_H_INCLUDED
 #define TRIGGER_UPDATE_PROTOS_H_INCLUDED
 
-STATICFNDCL boolean_t check_unique_trigger_name(char *trigvn, int trigvn_len, char *trigger_name, uint4 trigger_name_len);
-STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len, int *set_index,
-					     int *kill_index, boolean_t *set_cmp_result, boolean_t *kill_cmp_result,
-					     boolean_t *full_match, stringkey *set_trigger_hash, stringkey *kill_trigger_hash,
-					     mval *setname, mval *killname);
+STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char **values, uint4 *value_len,	/* input parm */
+						stringkey *set_trigger_hash, stringkey *kill_trigger_hash,	/* input parm */
+						int *set_index, int *kill_index, boolean_t *set_cmp_result,	/* output parm */
+						boolean_t *kill_cmp_result, boolean_t *full_match,		/* output parm */
+						mval *setname, mval *killname);					/* output parm */
 STATICFNDCL int4 modify_record(char *trigvn, int trigvn_len, char add_delete, int trigger_index, char **values, uint4 *value_len,
-			       mval *trigger_count, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash,
-			       stringkey *set_hash);
-STATICFNDCL int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigger_count, char *trigname_seq_str,
-				       uint4 seq_len);
+			       mval *trigger_count, boolean_t db_matched_set, boolean_t db_matched_kill, stringkey *kill_hash,
+			       stringkey *set_hash, int set_kill_bitmask);
+STATICFNDCL int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigger_count, char *trigname_seq_str, uint4 seq_len);
 STATICFNDCL int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_value, int trigindx, boolean_t add_kill_hash,
 					stringkey *kill_hash, stringkey *set_hash);
 STATICFNDCL int4 add_trigger_cmd_attributes(char *trigvn, int trigvn_len,  int trigger_index, char *trig_cmds, char **values,
-					    uint4 *value_len, boolean_t set_compare, boolean_t kill_compare, stringkey *kill_hash,
-					    stringkey *set_hash);
+						uint4 *value_len, boolean_t db_matched_set, boolean_t db_matched_kill,
+						stringkey *kill_hash, stringkey *set_hash, uint4 db_cmd_bm, uint4 tf_cmd_bm);
 STATICFNDCL int4 add_trigger_options_attributes(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char **values,
 						uint4 *value_len);
 STATICFNDCL boolean_t subtract_trigger_cmd_attributes(char *trigvn, int trigvn_len, char *trig_cmds, char **values,
 						      uint4 *value_len, boolean_t set_cmp, stringkey *kill_hash,
-						      stringkey *set_hash);
-STATICFNDCL boolean_t subtract_trigger_options_attributes(char *trigvn, int trigvn_len, char *trig_options, char *option_value);
+						      stringkey *set_hash, int trigger_index, uint4 db_cmd_bm, uint4 tf_cmd_bm);
 STATICFNDCL boolean_t validate_label(char *trigvn, int trigvn_len);
 STATICFNDCL int4 update_commands(char *trigvn, int trigvn_len, int trigger_index, char *new_trig_cmds, char *orig_db_cmds);
-STATICFNDCL int4 update_options(char *trigvn, int trigvn_len, int trigger_index, char *trig_options, char *option_value);
 STATICFNDCL int4 update_trigger_name(char *trigvn, int trigvn_len, int trigger_index, char *db_trig_name, char *tf_trig_name,
 				     uint4 tf_trig_name_len);
 STATICFNDCL boolean_t trigger_update_rec_helper(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats);
+
+boolean_t trigger_name_search(char *trigger_name, uint4 trigger_name_len, mval *val, gd_region **found_reg);
+boolean_t check_unique_trigger_name_full(char **values, uint4 *value_len, mval *val, boolean_t *new_match,
+				char *trigvn, int trigvn_len, stringkey *kill_trigger_hash, stringkey *set_trigger_hash);
 boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, uint4 *trig_stats, io_pair *trigfile_device,
 			     int4 *record_num);
+
+STATICFNDCL trig_stats_t trigupdrec_reg(char *trigvn, int trigvn_len, boolean_t *jnl_format_done, mval *trigjrec,
+	boolean_t *new_name_check_done, boolean_t *new_name_ptr, char **values, uint4 *value_len, char add_delete,
+	stringkey *kill_trigger_hash, stringkey *set_trigger_hash, char *disp_trigvn, int disp_trigvn_len, uint4 *trig_stats,
+	boolean_t *first_gtmio, char *utilprefix, int *utilprefixlen);
+
 boolean_t trigger_update(char *trigger_rec, uint4 len);
 #endif
diff --git a/sr_unix/trigger_upgrade.c b/sr_unix/trigger_upgrade.c
new file mode 100644
index 0000000..3eccd46
--- /dev/null
+++ b/sr_unix/trigger_upgrade.c
@@ -0,0 +1,542 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 GTM_TRIGGER
+#include "gdsroot.h"			/* for gdsfhead.h */
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"			/* for gdsfhead.h */
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include "filestruct.h"
+#include "trigger.h"
+#include <rtnhdr.h>			/* needed for gv_trigger.h */
+#include "gv_trigger.h"
+#include "gtm_trigger.h"
+#include "gv_trigger_protos.h"
+#include "trigger_upgrade_protos.h"
+#include "tp_restart.h"
+#include "change_reg.h"
+#include "targ_alloc.h"
+#include "mv_stent.h"
+#include "op.h"
+#include "tp_frame.h"
+#include "gvcst_protos.h"
+#include "gvsub2str.h"
+#include "mvalconv.h"
+#include "op_tcommit.h"
+#include "format_targ_key.h"
+#include "repl_msg.h"
+#include "gtmsource.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 "jnl.h"			/* for jnl_format prototype and for tp.h */
+#include "tp.h"				/* needed for T_BEGIN_SETORKILL_NONTP_OR_TP */
+#include "t_begin.h"
+#include "repl_sp.h"			/* for F_CLOSE (used by JNL_FD_CLOSE) */
+#include "gtmio.h"			/* for CLOSEFILE_RESET macro */
+
+GBLREF	gd_region	*gv_cur_region;
+GBLREF	uint4		dollar_tlevel;
+GBLREF	gv_key		*gv_currkey;
+GBLREF	unsigned int	t_tries;
+#ifdef DEBUG
+GBLREF	boolean_t	is_replicator;
+GBLREF	boolean_t	donot_INVOKE_MUMTSTART;
+#endif
+
+error_def(ERR_TRIGLOADFAIL);
+
+LITREF	mval		literal_batch;
+LITREF	mval		literal_hashlabel;
+LITREF	mval		literal_hashcycle;
+LITREF	mval		literal_hashcount;
+#define TRIGGER_SUBSDEF(SUBSTYPE, SUBSNAME, LITMVALNAME, TRIGFILEQUAL, PARTOFHASH)	LITREF mval LITMVALNAME;
+#include "trigger_subs_def.h"
+#undef TRIGGER_SUBSDEF
+
+DEFINE_NSB_CONDITION_HANDLER(trigger_upgrade_ch)
+
+STATICFNDCL void	gvtr_set_hasht_gblsubs(mval *subs_mval, mval *set_mval);
+STATICFNDEF void	gvtr_set_hashtrhash(char *trigvn, int trigvn_len, uint4 hash_code, int trigindx);
+
+STATICFNDEF void	gvtr_set_hasht_gblsubs(mval *subs_mval, mval *set_mval)
+{
+	uint4		curend;
+	boolean_t	was_null = FALSE, is_null = FALSE;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
+	assert(KEY_DELIMITER == gv_currkey->base[curend]);
+	assert(gv_target->gd_csa == cs_addrs);
+	COPY_SUBS_TO_GVCURRKEY(subs_mval, gv_cur_region, gv_currkey, was_null, is_null); /* updates gv_currkey */
+	MV_FORCE_STR(set_mval);
+	gvcst_put(set_mval);
+	gv_currkey->end = curend;	/* reset gv_currkey->end to what it was at function entry */
+	gv_currkey->base[curend] = KEY_DELIMITER;    /* restore terminator for entire key so key is well-formed */
+	return;
+}
+
+/* Set ^#t(<gbl>,"#TRHASH",hash_code,nnn)=<gbl>_$c(0)_trigindx where gv_currkey is ^#t(<gbl>).
+ * Note: This routine has code very similar to that in "add_trigger_hash_entry". There is just
+ * not enough commonality to justify merging the two.
+ */
+STATICFNDEF void	gvtr_set_hashtrhash(char *trigvn, int trigvn_len, uint4 hash_code, int trigindx)
+{
+	uint4		curend;
+	boolean_t	was_null = FALSE, is_null = FALSE;
+	mval		tmpmval, mv_indx, *mv_indx_ptr;
+	mval		mv_hash;
+	int		hash_indx, num_len;
+	char		name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
+	char		*ptr;
+	char		indx_str[MAX_DIGITS_IN_INT];
+	uint4		len;
+	int4		result;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	curend = gv_currkey->end; /* note down gv_currkey->end before changing it so we can restore it before function returns */
+	assert(KEY_DELIMITER == gv_currkey->base[curend]);
+	assert(gv_target->gd_csa == cs_addrs);
+	/* Set ^#t(<gvn>,"#TRHASH",kill_hash_code,i). To do that, first determine the
+	 * highest i such that ^#t(<gvn>,"#TRHASH",kill_hash_code,i) exists. Set
+	 * ^#t(<gvn>,"#TRHASH",kill_hash_code,i+1)=kill_hash_code in that case.
+	 */
+	MV_FORCE_UMVAL(&mv_hash, hash_code);
+	BUILD_HASHT_SUB_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, "", 0);
+	op_zprevious(&mv_indx);
+	mv_indx_ptr = &mv_indx;
+	hash_indx = (0 == mv_indx.str.len) ? 1 : (mval2i(mv_indx_ptr) + 1);
+	i2mval(mv_indx_ptr, hash_indx);
+	MV_FORCE_STR(mv_indx_ptr);
+	/* Prepare the value of the SET */
+	num_len = 0;
+	I2A(indx_str, num_len, trigindx);
+	assert(MAX_MIDENT_LEN >= trigvn_len);
+	memcpy(name_and_index, trigvn, trigvn_len);
+	ptr = name_and_index + trigvn_len;
+	*ptr++ = '\0';
+	memcpy(ptr, indx_str, num_len);
+	len = trigvn_len + 1 + num_len;
+	/* Do the SET */
+	SET_TRIGGER_GLOBAL_SUB_SUB_MSUB_MSUB_STR(trigvn, trigvn_len,
+		LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH), mv_hash, mv_indx, name_and_index, len, result);
+	assert(PUT_SUCCESS == result);
+	gv_currkey->end = curend;	/* reset gv_currkey->end to what it was at function entry */
+	gv_currkey->base[curend] = KEY_DELIMITER;    /* restore terminator for entire key so key is well-formed */
+	return;
+}
+
+/* Upgrade ^#t global in "reg" region */
+void	trigger_upgrade(gd_region *reg)
+{
+	boolean_t		trigger_status = TRIG_FAILURE;
+	boolean_t		est_first_pass, do_upgrade, is_defined;
+	boolean_t		was_null = FALSE, is_null = FALSE;
+	int			loopcnt;
+	int			seq_num, trig_seq_num;
+	DEBUG_ONLY(unsigned int	lcl_t_tries;)
+	enum cdb_sc		failure;
+	mval			label, *label_mv;
+	mval			tmpmval, xecuteimval, gvname, *tmpmv, *tmpmv2;
+	int4			result, tmpint4;
+	uint4			curend, gvname_prev, xecute_curend;
+	uint4			hash_code, kill_hash_code;
+	int			count, i, xecutei, tncount;
+	char			*trigname, *trigindex, *ptr;
+	char			name_and_index[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT];
+	char			trigvn[MAX_MIDENT_LEN + 1 + MAX_DIGITS_IN_INT], nullbyte[1];
+	uint4			trigname_len, name_index_len;
+	int			ilen;
+	sgmnt_addrs		*csa;
+	jnl_private_control	*jpc;
+	uint4			sts;
+	int			close_res;
+	mval			trigjrec;
+	char			trigger_rec[] = "; ^#t physical upgrade from #LABEL 2 to #LABEL 3 (no logical change)";
+	hash128_state_t		hash_state, kill_hash_state;
+	uint4			hash_totlen, kill_hash_totlen;
+#	ifdef DEBUG
+	int			save_dollar_tlevel;
+#	endif
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	assert(gv_cur_region == reg);
+	assert(!dollar_tlevel);	/* caller should have ensured this. this is needed as otherwise things get complicated. */
+	assert(!is_replicator);	/* caller should have ensured this. this is needed so we dont bump jnl_seqno (if replicating) */
+	csa = &FILE_INFO(reg)->s_addrs;
+	assert(csa->hdr->hasht_upgrade_needed);
+	/* If before-image journaling is turned on in this region (does not matter if replication is turned on or not),
+	 * once this transaction is done, we need to switch to new journal file and cut the back link because
+	 * otherwise it is possible for backward journal recovery (or rollback) or source server to encounter
+	 * the journal records generated in this ^#t-upgrade-transaction in which case they dont know to handle
+	 * it properly (e.g. rollback or backward recovery does not know to restore csa->hdr->hasht_upgrade_needed
+	 * if it rolls back this transaction). To achieve this, we set hold_onto_crit to TRUE and do the jnl link
+	 * cut AFTER the transaction commits but before anyone else can sneak in to do any more updates.
+	 * Since most often we expect databases to be journaled, we do this hold_onto_crit even for the non-journaled case.
+	 */
+	grab_crit(reg);
+	csa->hold_onto_crit = TRUE;
+	DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel);
+	assert(!donot_INVOKE_MUMTSTART);
+	DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE);
+	op_tstart(IMPLICIT_TSTART, TRUE, &literal_batch, 0); /* 0 ==> save no locals but RESTART OK */
+	ESTABLISH_NORET(trigger_upgrade_ch, est_first_pass);
+	/* On a TP restart anywhere down below, this line is where the restart resumes execution from */
+	assert(donot_INVOKE_MUMTSTART);	/* Make sure still set for every try/retry of TP transaction */
+	change_reg(); /* TP_CHANGE_REG wont work as we need to set sgm_info_ptr */
+	assert(NULL != cs_addrs);
+	assert(csa == cs_addrs);
+	SET_GVTARGET_TO_HASHT_GBL(csa);	/* sets up gv_target */
+	assert(NULL != gv_target);
+	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;	/* Needed to do every retry in case restart was due to an online rollback.
+						 * This also sets up gv_currkey */
+	/* Do actual upgrade of ^#t global.
+	 *
+	 * Below is a sample layout of the pre-upgrade ^#t global
+	 * -------------------------------------------------------
+	 * ^#t("#TNAME","x")="a"_$C(0)_"1"
+	 * ^#t("#TRHASH",89771515,1)="a"_$C(0)_"1"
+	 * ^#t("#TRHASH",106937755,1)="a"_$C(0)_"1"
+	 * ^#t("a",1,"BHASH")="106937755"
+	 * ^#t("a",1,"CHSET")="M"
+	 * ^#t("a",1,"CMD")="S"
+	 * ^#t("a",1,"LHASH")="89771515"
+	 * ^#t("a",1,"TRIGNAME")="x#"
+	 * ^#t("a",1,"XECUTE")=" do ^twork"
+	 * ^#t("a","#COUNT")="1"
+	 * ^#t("a","#CYCLE")="1"
+	 * ^#t("a","#LABEL")="2"
+	 *
+	 * Below is the upgraded layout of the same ^#t global
+	 * -------------------------------------------------------
+	 * ^#t("#LABEL")="3"
+	 * ^#t("#TNAME","x")="a"_$C(0)_"1"
+	 * ^#t("a",1,"BHASH")="71945627"
+	 * ^#t("a",1,"CHSET")="M"
+	 * ^#t("a",1,"CMD")="S"
+	 * ^#t("a",1,"LHASH")="71945627"
+	 * ^#t("a",1,"TRIGNAME")="x#"
+	 * ^#t("a",1,"XECUTE")=" do ^twork"
+	 * ^#t("a","#COUNT")="1"
+	 * ^#t("a","#CYCLE")="2"
+	 * ^#t("a","#LABEL")="3"
+	 * ^#t("a","#TRHASH",71945627,1)="a"_$C(0)_"1"
+	 *
+	 * Key aspects of the format change
+	 * ----------------------------------
+	 * 1) New ^#t("#LABEL")="3" to indicate the format of the ^#t global. This is in addition to
+	 * 	^#t("a","#LABEL") etc. which is already there. This way we have a #LABEL for not just the installed
+	 * 	triggers but also for the name information stored in the #TNAME nodes.
+	 * 2) In the BHASH and LHASH fields. The hash computation is different so there are more chances of BHASH and LHASH
+	 * 	matching in which case we store only one #TRHASH entry (instead of two). So thre is fewer ^#t records in the new
+	 * 	format in most cases.
+	 * 3) ^#t("a","#LABEL") bumps from 2 to 3. Similarly ^#t("a","#CYCLE") bumps by one (to make sure triggers for this
+	 *	global get re-read if and when we implement an -ONLINE upgrade).
+	 * 4) DEFAULT used to have ^#t("#TNAME",...) nodes corresponding to triggers across ALL regions in the gbldir and
+	 * 	other regions used to have NO ^#t("#TNAME",...) nodes whereas after the upgrade every region will have
+	 *	^#t("#TNAME",...) nodes	corresponding to triggers installed in that region. So it is safer to kill ^#t("#TNAME")
+	 *	nodes and add them as needed.
+	 * 5) #TRHASH has moved from ^#t() to ^#t(<gbl>). So it is safer to kill ^#t("#TRHASH")	nodes and add them as needed.
+	 */
+	tmpmv = &tmpmval;	/* At all points maintain this relationship. The two are used interchangeably below */
+	if (0 == gv_target->root)
+		do_upgrade = FALSE;
+	else
+	{	/* Check if ^#t("#LABEL") exists. If so, upgrade already done. No need to do it again. */
+		is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashlabel, tmpmv);
+		assert(!is_defined
+			|| (MV_IS_STRING(tmpmv) && (tmpmval.str.len == STR_LIT_LEN(HASHT_GBL_CURLABEL))
+				&& !MEMCMP_LIT(tmpmval.str.addr, HASHT_GBL_CURLABEL)));
+		do_upgrade = !is_defined;
+	}
+	/* The below logic assumes ^#t global does not have any integrity errors */
+	assert(do_upgrade);	/* caller should have not invoked us otherwise */
+	if (do_upgrade)
+	{	/* kill ^#t("#TRHASH") and ^#t("#TNAME") first. These will be generated again as we process ^#t(<gbl>,...) nodes */
+		csa->incr_db_trigger_cycle = TRUE; /* so that we increment csd->db_trigger_cycle at commit time.
+							 * this will force concurrent processes to read upgraded triggers.
+							 */
+		if (JNL_WRITE_LOGICAL_RECS(csa))
+		{	/* Note that the ^#t upgrade is a physical layout change. But it has no logical change (i.e. users
+			 * will see the same MUPIP TRIGGER -SELECT output as before). So write only a dummy LGTRIG journal
+			 * record for this operation. Hence write a string that starts with a trigger comment character ";".
+			 */
+			assert(!gv_cur_region->read_only);
+			trigjrec.mvtype = MV_STR;
+			trigjrec.str.len = STRLEN(&trigger_rec[0]);
+			trigjrec.str.addr = &trigger_rec[0];
+			jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
+		}
+		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
+		if (0 != gvcst_data())
+			gvcst_kill(TRUE);
+		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
+		if (0 != gvcst_data())
+			gvcst_kill(TRUE);
+		/* Loop through all global names for which ^#t(<gvn>) exists. The only first-level subscripts of ^#t starting
+		 * with # are #TNAME and #TRHASH in collation order. So after #TRHASH we expect to find subscripts that are
+		 * global names. Hence the HASHTRHASH code is placed AFTER the HASHTNAME code above.
+		 */
+		TREF(gd_targ_gvnh_reg) = NULL;	/* needed so op_gvorder below goes through gvcst_order (i.e. focuses only
+						 * on the current region) and NOT through gvcst_spr_order (which does not
+						 * apply anyways in the case of ^#t).
+						 */
+		nullbyte[0] = '\0';
+		do
+		{
+			op_gvorder(&gvname);
+			if (0 == gvname.str.len)
+				break;
+			assert(ARRAYSIZE(trigvn) > gvname.str.len);
+			memcpy(&trigvn[0], gvname.str.addr, gvname.str.len);
+			gvname.str.addr = &trigvn[0];	/* point away from stringpool to avoid stp_gcol issues */
+			/* Save gv_currkey->prev so it is restored before next call to op_gvorder (which cares about this field).
+			 * gv_currkey->prev gets tampered with in the for loop below (e.g. BUILD_HASHT_SUB_CURRKEY macro).
+			 * No need to do this for gv_currkey->end since the body of the for loop takes care of restoring it.
+			 */
+			gvname_prev = gv_currkey->prev;
+			BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+			/* At this point, gv_currkey is ^#t(<gvn>) */
+			/* Increment ^#t(<gvn>,"#CYCLE") */
+			is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcycle, tmpmv);
+			assert(is_defined);
+			tmpint4 = mval2i(tmpmv);
+			tmpint4++;
+			i2mval(tmpmv, tmpint4);
+			gvtr_set_hasht_gblsubs((mval *)&literal_hashcycle, tmpmv);
+			/* Read ^#t(<gvn>,"#COUNT") */
+			is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcount, tmpmv);
+			if (is_defined)
+			{
+				tmpint4 = mval2i(tmpmv);
+				count = tmpint4;
+			} else
+				count = 0;
+			/* Set ^#t(<gvn>,"#LABEL")=3 */
+			tmpmval.mvtype = MV_STR;
+			tmpmval.str.addr = HASHT_GBL_CURLABEL;
+			tmpmval.str.len = STRLEN(HASHT_GBL_CURLABEL);
+			gvtr_set_hasht_gblsubs((mval *)&literal_hashlabel, tmpmv);
+			/* At this point, gv_currkey is ^#t(<gvn>) */
+			for (i = 1; i <= count; i++)
+			{
+				/* At this point, gv_currkey is ^#t(<gvn>) */
+				curend = gv_currkey->end; /* note gv_currkey->end before changing it so we can restore it later */
+				assert(KEY_DELIMITER == gv_currkey->base[curend]);
+				assert(gv_target->gd_csa == cs_addrs);
+				i2mval(tmpmv, i);
+				COPY_SUBS_TO_GVCURRKEY(tmpmv, gv_cur_region, gv_currkey, was_null, is_null);
+				/* At this point, gv_currkey is ^#t(<gvn>,i) */
+				/* Compute new LHASH and BHASH hash values.
+				 *	LHASH uses : GVSUBS, XECUTE
+				 *	BHASH uses : GVSUBS, XECUTE, DELIM, ZDELIM, PIECES
+				 * So reach each of these pieces and compute hash along the way.
+				 */
+				STR_PHASH_INIT(hash_state, hash_totlen);
+				STR_PHASH_PROCESS(hash_state, hash_totlen, gvname.str.addr, gvname.str.len);
+				STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+				/* Read in ^#t(<gvn>,i,"GVSUBS") */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_gvsubs, tmpmv);
+				if (is_defined)
+				{
+					STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+					STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+				}
+				/* Copy over SET hash state (2-tuple <state,totlen>) to KILL hash state before adding
+				 * the PIECES, DELIM, ZDELIM portions (those are only part of the SET hash).
+				 */
+				kill_hash_state = hash_state;
+				kill_hash_totlen = hash_totlen;
+				/* Read in ^#t(<gvn>,i,"PIECES") */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_pieces, tmpmv);
+				if (is_defined)
+				{
+					STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+					STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+				}
+				/* Read in ^#t(<gvn>,i,"DELIM") */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_delim, tmpmv);
+				if (is_defined)
+				{
+					STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+					STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+				}
+				/* Read in ^#t(<gvn>,i,"ZDELIM") */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_zdelim, tmpmv);
+				if (is_defined)
+				{
+					STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+					STR_PHASH_PROCESS(hash_state, hash_totlen, nullbyte, 1);
+				}
+				/* Read in ^#t(<gvn>,i,"XECUTE").
+				 * Note: The XECUTE portion of the trigger definition is used in SET and KILL hash.
+				 * But since we have started maintaining "hash_state" and "kill_hash_state" separately
+				 * (due to PIECES, DELIM, ZDELIM) we need to update the hash for both using same input string.
+				 */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_xecute, tmpmv);
+				if (is_defined)
+				{
+					STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+					STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+				} else
+				{	/* Multi-line XECUTE string */
+					/* At this point, gv_currkey is ^#t(<gvn>,i) */
+					xecute_curend = gv_currkey->end; /* note gv_currkey->end so we can restore it later */
+					assert(KEY_DELIMITER == gv_currkey->base[xecute_curend]);
+					tmpmv2 = (mval *)&literal_xecute;
+					COPY_SUBS_TO_GVCURRKEY(tmpmv2, gv_cur_region, gv_currkey, was_null, is_null);
+					xecutei = 1;
+					do
+					{
+						i2mval(&xecuteimval, xecutei);
+						is_defined = gvtr_get_hasht_gblsubs(&xecuteimval, tmpmv);
+						if (!is_defined)
+							break;
+						STR_PHASH_PROCESS(hash_state, hash_totlen, tmpmval.str.addr, tmpmval.str.len);
+						STR_PHASH_PROCESS(kill_hash_state, kill_hash_totlen,
+									tmpmval.str.addr, tmpmval.str.len);
+						xecutei++;
+					} while (TRUE);
+					/* Restore gv_currkey to ^#t(<gvn>,i) */
+					gv_currkey->end = xecute_curend;
+					gv_currkey->base[xecute_curend] = KEY_DELIMITER;
+				}
+				STR_PHASH_RESULT(hash_state, hash_totlen, hash_code);
+				STR_PHASH_RESULT(kill_hash_state, kill_hash_totlen, kill_hash_code);
+				/* Set ^#t(<gvn>,i,"LHASH") */
+				i2mval(tmpmv, kill_hash_code);
+				gvtr_set_hasht_gblsubs((mval *)&literal_lhash, tmpmv);
+				/* Set ^#t(<gvn>,i,"BHASH") */
+				i2mval(tmpmv, hash_code);
+				gvtr_set_hasht_gblsubs((mval *)&literal_bhash, tmpmv);
+				/* Read in ^#t(<gvn>,i,"TRIGNAME") to determine if #SEQNUM/#TNCOUNT needs to be maintained */
+				is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_trigname, tmpmv);
+				assert(is_defined);
+				assert('#' == tmpmval.str.addr[tmpmval.str.len - 1]);
+				tmpmval.str.len--;
+				if (NULL != (ptr = memchr(tmpmval.str.addr, '#', tmpmval.str.len)))
+				{	/* Auto-generated name. Need to maintain #SEQNUM/#TNCOUNT */
+					/* Take copy of trigger name into non-stringpool location to avoid stp_gcol issues */
+					trigname_len = ptr - tmpmval.str.addr;
+					ptr++;
+					name_index_len = (tmpmval.str.addr + tmpmval.str.len) - ptr;
+					assert(ARRAYSIZE(name_and_index) >= (trigname_len + 1 + name_index_len));
+					trigname = &name_and_index[0];
+					trigindex = ptr;
+					memcpy(trigname, tmpmval.str.addr, tmpmval.str.len);
+					A2I(ptr, ptr + name_index_len, trig_seq_num);
+					/* At this point, gv_currkey is ^#t(<gvn>,i) */
+					/* $get(^#t("#TNAME",GVN,"#SEQNUM")) */
+					BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+						trigname, trigname_len, LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM));
+					seq_num = gvcst_get(tmpmv) ? mval2i(tmpmv) : 0;
+					if (trig_seq_num > seq_num)
+					{	/* Set ^#t("#TNAME",GVN,"#SEQNUM") = trig_seq_num */
+						SET_TRIGGER_GLOBAL_SUB_SUB_SUB_STR(LITERAL_HASHTNAME,
+							STR_LIT_LEN(LITERAL_HASHTNAME), trigname, trigname_len,
+							LITERAL_HASHSEQNUM, STR_LIT_LEN(LITERAL_HASHSEQNUM),
+							trigindex, name_index_len, result);
+						assert(PUT_SUCCESS == result);
+					}
+					/* set ^#t("#TNAME",GVN,"#TNCOUNT")++ */
+					BUILD_HASHT_SUB_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+						trigname, trigname_len, LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT));
+					tncount = gvcst_get(tmpmv) ? mval2i(tmpmv) + 1 : 1;
+					i2mval(tmpmv, tncount);
+					SET_TRIGGER_GLOBAL_SUB_SUB_SUB_MVAL(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+						trigname, trigname_len, LITERAL_HASHTNCOUNT, STR_LIT_LEN(LITERAL_HASHTNCOUNT),
+						tmpmval, result);
+					trigname_len += 1 + name_index_len; /* in preparation for ^#t("#TNAME") set below */
+					assert(PUT_SUCCESS == result);
+					BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+					/* At this point, gv_currkey is ^#t(<gvn>) */
+				} else
+				{
+					/* Take copy of trigger name into non-stringpool location to avoid stp_gcol issues */
+					trigname = &name_and_index[0];
+					trigname_len = tmpmval.str.len;  /* in preparation for ^#t("#TNAME") set below */
+					assert(ARRAYSIZE(name_and_index) > trigname_len);
+					memcpy(trigname, tmpmval.str.addr, trigname_len);
+					/* Restore gv_currkey to what it was at beginning of for loop iteration */
+					gv_currkey->end = curend;
+					gv_currkey->base[curend] = KEY_DELIMITER;
+				}
+				/* At this point, gv_currkey is ^#t(<gvn>) */
+				if (kill_hash_code != hash_code)
+					gvtr_set_hashtrhash(gvname.str.addr, gvname.str.len, kill_hash_code, i);
+				/* Set ^#t(<gvn>,"#TRHASH",hash_code,i) */
+				gvtr_set_hashtrhash(gvname.str.addr, gvname.str.len, hash_code, i);
+				/* Set ^#t("#TNAME",<trigname>)=<gvn>_$c(0)_<trigindx> */
+				/* The upgrade assumes that the region does not contain two triggers with the same name.
+				 * V62000 and before could potentially have this out of design case. Once implemented
+				 * the trigger integrity check will warn users of this edge case */
+				ptr = &trigvn[gvname.str.len];
+				*ptr++ = '\0';
+				ilen = 0;
+				I2A(ptr, ilen, i);
+				ptr += ilen;
+				assert(ptr <= ARRAYTOP(trigvn));
+				SET_TRIGGER_GLOBAL_SUB_SUB_STR(LITERAL_HASHTNAME, STR_LIT_LEN(LITERAL_HASHTNAME),
+					trigname, trigname_len, trigvn, ptr - gvname.str.addr, result);
+				assert(PUT_SUCCESS == result);
+				BUILD_HASHT_SUB_CURRKEY(gvname.str.addr, gvname.str.len);
+				/* At this point, gv_currkey is ^#t(<gvn>) */
+			}
+			/* At this point, gv_currkey is ^#t(<gvn>) i.e. gv_currkey->end is correct but gv_currkey->prev
+			 * might have been tampered with. Restore it to proper value first.
+			 */
+			 gv_currkey->prev = gvname_prev;
+		} while (TRUE);
+		/* set ^#t("#LABEL")=3 */
+		label_mv = &label;
+		MV_FORCE_MVAL(label_mv, 3);
+		SET_TRIGGER_GLOBAL_SUB_MVAL(LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL), label, result);
+		assert(PUT_SUCCESS == result);		/* Size of count can only get shorter or stay the same */
+	}
+	op_tcommit();
+	REVERT; /* remove our condition handler */
+	DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE;)
+	if (csa->hold_onto_crit)
+	{
+		assert(csa->now_crit);	/* we should still hold crit */
+		/* Switch to new journal file and cut previous link if we did ^#t upgrade on a journaled region */
+		if (do_upgrade && JNL_WRITE_LOGICAL_RECS(csa))
+		{
+			sts = set_jnl_file_close(0);
+			assert(SS_NORMAL == sts);	/* because we should have done jnl_ensure_open already
+							 * in which case set_jnl_file_close has no way of erroring out.
+							 */
+			sts = jnl_file_open_switch(reg, 0);
+			if (sts)
+			{
+				jpc = csa->jnl;
+				if (NOJNL != jpc->channel)
+					JNL_FD_CLOSE(jpc->channel, close_res);	/* sets jpc->channel to NOJNL */
+				assert(NOJNL == jpc->channel);
+				jnl_send_oper(jpc, sts);
+			}
+		}
+		csa->hold_onto_crit = FALSE;
+	} else
+		grab_crit(reg);
+	csa->hdr->hasht_upgrade_needed = FALSE;
+	rel_crit(reg);
+	return;	/* if any errors happen during upgrade (e.g. TRANS2BIG), we will not reach here */
+}
+#endif /* GTM_TRIGGER */
diff --git a/sr_unix/do_shmat.h b/sr_unix/trigger_upgrade_protos.h
similarity index 69%
copy from sr_unix/do_shmat.h
copy to sr_unix/trigger_upgrade_protos.h
index c4143a7..c694422 100644
--- a/sr_unix/do_shmat.h
+++ b/sr_unix/trigger_upgrade_protos.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -9,9 +9,9 @@
  *								*
  ****************************************************************/
 
-#ifndef __DO_SHMAT_H__
-#define __DO_SHMAT_H__
+#ifndef TRIGGER_UPGRADE_PROTOS_H_INCLUDED
+#define TRIGGER_UPGRADE_PROTOS_H_INCLUDED
 
-void *do_shmat(int4 shmid, const void *shmaddr, int4 shmflg);
+void	trigger_upgrade(gd_region *reg);
 
 #endif
diff --git a/sr_unix/util_out_print_gtmio.c b/sr_unix/util_out_print_gtmio.c
new file mode 100644
index 0000000..a9b476a
--- /dev/null
+++ b/sr_unix/util_out_print_gtmio.c
@@ -0,0 +1,134 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 GTM_TRIGGER
+#include "gtm_string.h"
+
+#include "util.h"		/* for FLUSH and util_out_print */
+#include "util_out_print_vaparm.h"
+#include "op.h"			/* for op_write prototype */
+#include "io.h"			/* needed for io_pair typedef */
+#include "gtmimagename.h"	/* for IS_MCODE_RUNNING */
+
+GBLREF	uint4			dollar_tlevel;
+
+#define	ZTRIGBUFF_INIT_ALLOC		1024	/* start at 1K */
+#define	ZTRIGBUFF_INIT_MAX_GEOM_ALLOC	1048576	/* stop geometric growth at this value */
+
+/* Used by MUPIP TRIGGER or $ZTRIGGER routines to buffer trigger output until TCOMMIT time
+ * (as otherwise we might display stale output due to a restarted try).
+ */
+void	util_out_print_gtmio(caddr_t message, int flush, ...)
+{
+	va_list		var;
+	char		*src, *dst, *newdst;
+	int		srclen, dstlen, dstalloc, newlen, ptrlen;
+	caddr_t		msg;
+	int4		msglen;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	/* we expect all trigger operations (SELECT, LOAD, etc.) to happen inside TP. exceptions should set TREF variable */
+	assert(dollar_tlevel || TREF(gtmio_skip_tlevel_assert));
+	va_start(var, flush);
+	/* If "!AD" has been specified as the message, skip the util_out_print_vaparm call as it is possible
+	 * the input string length is > the maximum length util_out_* routines are designed to handle.
+	 * In that case, we dont need the parameter substitution anyways so do a memcpy instead.
+	 */
+	if (STRCMP(message, "!AD") || (FLUSH != flush))
+	{
+		util_out_print_vaparm(message, NOFLUSH, var, MAXPOSINT4);
+		src = TREF(util_outbuff_ptr);
+		assert(NULL != TREF(util_outptr));
+		srclen = INTCAST(TREF(util_outptr) - src) + 1;	/* 1 is for '\n' */
+		assert(OUT_BUFF_SIZE >= srclen);
+	} else
+	{
+		srclen = (int)va_arg(var, int4) + 1;
+		src = (char *)va_arg(var, caddr_t);
+	}
+	if (FLUSH == flush)
+	{
+		dstalloc = TREF(ztrigbuffAllocLen);
+		dstlen = TREF(ztrigbuffLen);
+		/* Leave room for terminating '\0' (after the \n) for later use in FPRINTF in tp_ztrigbuff_print.
+		 * Hence the use of "<=" instead of a "<" in the "if (dstalloc <= (dstlen + srclen))" check below.
+		 */
+		if (dstalloc <= (dstlen + srclen))
+		{	/* reallocate */
+			dst = TREF(ztrigbuff);
+			do
+			{
+				if (!dstalloc)
+					dstalloc = ZTRIGBUFF_INIT_ALLOC;	/* Allocate a 1K buffer at start */
+				else if (ZTRIGBUFF_INIT_MAX_GEOM_ALLOC <= dstalloc)
+					dstalloc += ZTRIGBUFF_INIT_MAX_GEOM_ALLOC;
+				else
+					dstalloc = dstalloc * 2; /* grow geometrically until a limit and linearly after that */
+			} while (dstalloc <= (dstlen + srclen));
+			newdst = malloc(dstalloc);
+			if (dstlen)
+				memcpy(newdst, dst, dstlen);
+			TREF(ztrigbuff) = newdst;
+			TREF(ztrigbuffAllocLen) = dstalloc;
+			if (NULL != dst)
+				free(dst);
+		}
+		dst = TREF(ztrigbuff);
+		memcpy(dst + dstlen, src, srclen - 1);
+		dst[dstlen + srclen - 1] = '\n';
+		TREF(ztrigbuffLen) += srclen;
+		TREF(util_outptr) = TREF(util_outbuff_ptr);	/* Signal text is flushed */
+	}
+	va_end(TREF(last_va_list_ptr));
+	va_end(var);
+}
+
+void	tp_ztrigbuff_print(void)
+{
+	mval		flushtxt;
+	char		*ptr, *ptrtop, *ptr2;
+	int		len;
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	/* If mumps process doing trigger operations, use GTM IO routines. If not use util_out_print. The only
+	 * exception is if the MUPIP caller wants to use current IO device (i.e. it has it all set up). In that
+	 * case the TREF ztrig_use_io_curr_device would have been set to TRUE.
+	 */
+	if (IS_MCODE_RUNNING || TREF(ztrig_use_io_curr_device))
+	{
+		ptr = TREF(ztrigbuff);
+		assert('\n' == ptr[TREF(ztrigbuffLen) - 1]);
+		ptrtop = ptr + TREF(ztrigbuffLen);
+		flushtxt.mvtype = MV_STR;
+		do
+		{
+			len = INTCAST(ptrtop - ptr);
+			ptr2 = memchr(ptr, '\n', len);
+			assert(NULL != ptr2);
+			flushtxt.str.addr = ptr;
+			flushtxt.str.len = ptr2 - ptr;
+			op_write(&flushtxt);
+			op_wteol(1);
+			ptr = ptr2 + 1;
+		} while (ptr < ptrtop);
+	} else
+	{	/* Use util_out_print but since you pass TRUE for flush, use -1 to prevent duplicate newline */
+		assert('\n' == (TREF(ztrigbuff))[TREF(ztrigbuffLen) - 1]);
+		assert(TREF(ztrigbuffLen) < TREF(ztrigbuffAllocLen));
+		(TREF(ztrigbuff))[TREF(ztrigbuffLen)] = '\0';
+		FPRINTF(stderr, "%s", TREF(ztrigbuff));
+	}
+}
+#endif
diff --git a/sr_unix/util_output.c b/sr_unix/util_output.c
index be3899a..1ad3804 100644
--- a/sr_unix/util_output.c
+++ b/sr_unix/util_output.c
@@ -65,12 +65,13 @@ GBLREF	boolean_t		is_updproc;
 GBLREF	boolean_t		is_updhelper;
 GBLREF  recvpool_addrs          recvpool;
 GBLREF  uint4                   process_id;
-GBLREF	void			(*op_write_ptr)(mval *v);
-GBLREF	void			(*op_wteol_ptr)(int4 n);
 
 error_def(ERR_REPLINSTACC);
 error_def(ERR_TEXT);
 
+#define	ZTRIGBUFF_INIT_ALLOC		1024	/* start at 1K */
+#define	ZTRIGBUFF_INIT_MAX_GEOM_ALLOC	1048576	/* stop geometric growth at this value */
+
 #define GETFAOVALDEF(faocnt, var, type, result, defval) \
 	if (faocnt > 0) {result = (type)va_arg(var, type); faocnt--;} else result = defval;
 
@@ -739,8 +740,7 @@ void	util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
 	SETUP_THREADGBL_ACCESS;
 	if (IS_GTMSECSHR_IMAGE && (FLUSH == flush))
 		flush = OPER;			/* All gtmsecshr origin msgs go to operator log */
-	if (NULL == TREF(util_outptr))
-		TREF(util_outptr) = TREF(util_outbuff_ptr);
+	assert(NULL != TREF(util_outptr));
 	if (NULL != message)
 	{
 		util_avail_len = INTCAST(TREF(util_outbuff_ptr) + OUT_BUFF_SIZE - TREF(util_outptr) - 2);
@@ -798,7 +798,6 @@ void	util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
 				case FLUSH:
 					if (use_stdio)
 					{
-						assert(NULL != op_write_ptr);
 						flushtxt.addr = fmt_buff;
 						flushtxt.len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
 						save_io_curr_device = io_curr_device;
@@ -848,36 +847,29 @@ void	util_out_print(caddr_t message, int flush, ...)
 	va_end(var);
 }
 
-/* Used primarily by MUPIP in the MUPIP TRIGGER routines where output can either be output "normally" there or
- * when the same trigger parsing/loading functions are called from within GTM, the output is done with GTM IO
- * routines.
+/* Saves a copy of the current unflushed buffer in util_outbuff_ptr into dst.
+ * The length of the allocated buffer at "dst" is passed in as *dst_len.
+ * If that length is not enough to store the unflushed buffer, FALSE is returned right away.
+ * If not, the length of the unflushed buffer is stored in dst_len, the actual unflushed buffer
+ * is copeid over to "dst", and a TRUE is returned.
  */
-void	util_out_print_gtmio(caddr_t message, int flush, ...)
+boolean_t	util_out_save(char *dst, int *dstlen_ptr)
 {
-	int		flush_it;
-	boolean_t	usestdio;
-	va_list		var;
-	mval		flushtxt;
+	int	srclen, dstlen;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	va_start(var, flush);
-	usestdio = IS_MCODE_RUNNING;
-	assert((FLUSH == flush) || (NOFLUSH == flush));
-	flush_it = ((FLUSH == flush) && !usestdio) ? FLUSH : NOFLUSH;
-	util_out_print_vaparm(message, flush_it, var, MAXPOSINT4);
-	if (usestdio && (FLUSH == flush))
-	{	/* Message should be in buffer and we just need to flush it */
-		assert(NULL != op_write_ptr);
-		flushtxt.mvtype = MV_STR;
-		flushtxt.str.addr = TREF(util_outbuff_ptr);
-		flushtxt.str.len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
-		(*op_write_ptr)(&flushtxt);
-		(*op_wteol_ptr)(1);
-		TREF(util_outptr) = TREF(util_outbuff_ptr);	/* Signal text is flushed */
-	}
-	va_end(TREF(last_va_list_ptr));
-	va_end(var);
+	assert(NULL != TREF(util_outptr));
+	srclen = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
+	assert(0 <= srclen);
+	assert(OUT_BUFF_SIZE >= srclen);
+	dstlen = *dstlen_ptr;
+	assert(0 <= dstlen);
+	if (srclen > dstlen)
+		return FALSE;
+	*dstlen_ptr = srclen;
+	memcpy(dst, TREF(util_outbuff_ptr), srclen);
+	return TRUE;
 }
 
 /* If $x of the standard output device is non-zero, and we are going to flush a buffer,
diff --git a/sr_unix/wcs_flu.c b/sr_unix/wcs_flu.c
index 0daea70..79e038a 100644
--- a/sr_unix/wcs_flu.c
+++ b/sr_unix/wcs_flu.c
@@ -47,15 +47,15 @@
 #include "anticipatory_freeze.h"
 #include "eintr_wrappers.h"
 
-GBLREF	gd_region	*gv_cur_region;
-GBLREF	uint4		process_id;
-GBLREF	sgmnt_addrs	*cs_addrs;
-GBLREF	volatile int4	db_fsync_in_prog;	/* for DB_FSYNC macro usage */
-GBLREF 	jnl_gbls_t	jgbl;
-GBLREF 	bool		in_backup;
+GBLREF	bool			in_backup;
+GBLREF	gd_region		*gv_cur_region;
+GBLREF	sgmnt_addrs		*cs_addrs;
+GBLREF	uint4			process_id;
+GBLREF	volatile int4		db_fsync_in_prog;	/* for DB_FSYNC macro usage */
+GBLREF	jnl_gbls_t		jgbl;
 #ifdef DEBUG
-GBLREF	boolean_t	in_mu_rndwn_file;
-GBLREF	boolean_t	mupip_jnl_recover;
+GBLREF	boolean_t		in_mu_rndwn_file;
+GBLREF	boolean_t		mupip_jnl_recover;
 #endif
 
 error_def(ERR_DBFILERR);
@@ -151,6 +151,7 @@ error_def(ERR_WRITERSTUCK);
 
 #define REL_CRIT_BEFORE_RETURN			\
 {						\
+	cnl->doing_epoch = FALSE;		\
 	cnl->wcsflu_pid = 0;			\
 	if (!was_crit)				\
 		rel_crit(gv_cur_region);	\
@@ -215,8 +216,15 @@ boolean_t wcs_flu(uint4 options)
 	if (jnl_enabled)
 	{
 		jb = jpc->jnl_buff;
-		/* Assert that we aren't trying to flush a completed journal file */
-		assert(!jb->last_eof_written);
+		/* If we are trying to flush a completed journal file, make sure there is nothing else to do and return. */
+		if (jb->last_eof_written)
+		{
+			assert(jb->fsync_dskaddr == jb->freeaddr);
+			assert((dba_bg != csd->acc_meth)
+				|| (!cnl->wcs_active_lvl && !csa->acc_meth.bg.cache_state->cacheq_active.fl));
+			REL_CRIT_BEFORE_RETURN;
+			return TRUE;
+		}
 		/* Assert that we never flush the cache in the midst of a database commit. The only exception is MUPIP RUNDOWN */
 		assert((csa->ti->curr_tn == csa->ti->early_tn) || in_mu_rndwn_file);
 		if (!jgbl.dont_reset_gbl_jrec_time)
@@ -246,6 +254,7 @@ boolean_t wcs_flu(uint4 options)
 	if (jnl_enabled)
 	{
 		assert(SS_NORMAL == jnl_status);
+		cnl->doing_epoch = sync_epoch || write_epoch;
 		epoch_already_current = (jb->post_epoch_freeaddr == jb->freeaddr);	/* crit held, so this stays valid */
 		if (return_early = (speedup_nobefore && !csd->jnl_before_image))
 		{	/* Finish easiest option first. This database has NOBEFORE image journaling and caller has asked for
@@ -444,6 +453,7 @@ boolean_t wcs_flu(uint4 options)
 						 * will get confused (see explanation above where variable "in_commit" gets set).
 						 */
 						assert(was_crit);	/* so dont need to rel_crit */
+						cnl->doing_epoch = FALSE;
 						cnl->wcsflu_pid = 0;
 						return FALSE;
 					}
diff --git a/sr_unix/zhist.c b/sr_unix/zhist.c
index 3e333a7..af4fd11 100644
--- a/sr_unix/zhist.c
+++ b/sr_unix/zhist.c
@@ -15,10 +15,9 @@
 
 #include "min_max.h"
 #include <rtnhdr.h>
-#include "zhist.h"
 #include "gtmlink.h"
 
-#ifdef USHBIN_SUPPORTED /* This entire file */
+#ifdef AUTORELINK_SUPPORTED /* This entire file */
 
 /* Routine called from op_rhd_ext() to determine if the routine being called needs to be relinked. To return TRUE,
  * the following conditions must be met:
@@ -37,77 +36,100 @@
 boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist)
 {
 	zro_validation_entry	*iter;
-	uint4			cur_cycle;
+	uint4			cur_cycle, rtnnmlen;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	assert(NULL != zhist);		/* Should be called unless relinking is possible */
+	assert(NULL != zhist);		/* Shouldn't be called unless relinking is possible */
 	/* TODO: Do this check second, if below logic would return TRUE */
 	if ((LINK_NORECURSIVE == TREF(relink_allowed)) && on_stack(rtnhdr, NULL))
 		return FALSE;	/* can't relink, or else we'll get LOADRUNNING */
-	/* If SET=$ZRO cycle has changed since validation list was compiled, recreate the list.... just fully relink */
-	/* TODO: Only relink when absolutely necessary. If routine has same hash in same location, don't relink */
+	/* If $ZROUTINES cycle has changed since validation list was created, signal relink but the relink only
+	 * actually happens if the file op_zlink() locates has a different object hashcode than the currently
+	 * linked routine - else it just rebuilds the history and calls it good.
+	 */
 	if (zhist->zroutines_cycle != TREF(set_zroutines_cycle))
 		return TRUE;
 	/* Traverse list corresponding to zro entries */
 	for (iter = &zhist->base[0]; iter != zhist->end; iter++)
 	{
-		/* TODO: assert routine name near cycle_reladdr == current routine invocation */
-		cur_cycle = RELINKCTL_CYCLE_READ(iter->relinkctl_bkptr, iter->cycle_loc);
+		DEBUG_ONLY(rtnnmlen = mid_len(&iter->relinkrec->rtnname_fixed));
+		assert((rtnnmlen == rtnhdr->routine_name.len)	/* Verify have the right entry - compare names */
+		       && (0 == memcmp(&iter->relinkrec->rtnname_fixed, rtnhdr->routine_name.addr, rtnnmlen)));
+		cur_cycle = iter->relinkrec->cycle;
 		if (cur_cycle != iter->cycle)
 			return TRUE;
 	}
 	return FALSE;
 }
 
-/* Routine called from zro_search()
- * zro_zhist_saverecent
- * INPUT:
- * 	array of history entries created during zro_search()
- * OUTPUT:
- * 	global variable TREF(recent_zhist), which is then "passed" to incr_link, which associates this history with routine hdr
+/* Routine called from zro_search_hist() to copy a given search history block from stack memory to malloc'd memory
+ * so it can be attached to the routine header of the linked routine.
+ *
+ * Parameters:
+ *   zhist_valent      - Last search history entry + 1
+ *   zhist_valent_base - First search history entry
+ *
+ * Return value:
+ *   Malloc'd block of search history header (zro_hist *) followed by the array of search history entries for
+ *   the given routine.
  */
-void zro_zhist_saverecent(zro_validation_entry *zhent, zro_validation_entry *zhent_base)
+zro_hist *zro_zhist_saverecent(zro_search_hist_ent *zhist_valent_end, zro_search_hist_ent *zhist_valent_base)
 {
-	int		hist_len;
-	zro_hist	*lcl_recent_zhist;
+	int			hist_len;
+	relinkrec_t		*rec;
+	zro_hist		*lcl_recent_zhist;
+	zro_validation_entry	*zhent;
+	zro_search_hist_ent	*zhist_valent;
+	mstr			rtnname;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
-	/* Malloc and save zhist copy */
-	assert(NULL != zhent);
-	assert(NULL != zhent_base);
-	hist_len = zhent - zhent_base;
-	lcl_recent_zhist = (zro_hist *)malloc(SIZEOF(zro_hist) + SIZEOF(zro_validation_entry) * hist_len);
+	/* Malloc and return zhist copy */
+	assert(NULL != zhist_valent_end);
+	assert(NULL != zhist_valent_base);
+	hist_len = zhist_valent_end - zhist_valent_base;
+	lcl_recent_zhist = (zro_hist *)malloc(SIZEOF(zro_hist) + (SIZEOF(zro_validation_entry) * hist_len));
 	lcl_recent_zhist->zroutines_cycle = TREF(set_zroutines_cycle);
 	lcl_recent_zhist->end = &lcl_recent_zhist->base[0] + hist_len;
-	memcpy((char *)&lcl_recent_zhist->base[0], (char *)zhent_base, SIZEOF(zro_validation_entry) * hist_len);
-	TREF(recent_zhist) = lcl_recent_zhist;
+	for (zhist_valent = zhist_valent_base, zhent = &lcl_recent_zhist->base[0];
+		0 < hist_len;
+			zhist_valent++, zhent++, hist_len--)
+	{
+		rtnname.addr = zhist_valent->rtnname.c;
+		rtnname.len = zhist_valent->rtnname_len;
+		assert(NULL != zhist_valent->zro_valent.relinkctl_bkptr);
+		rec = relinkctl_insert_record(zhist_valent->zro_valent.relinkctl_bkptr, &rtnname);
+		assert(NULL != rec);
+		zhist_valent->zro_valent.relinkrec = rec;
+		zhist_valent->zro_valent.cycle = rec->cycle;
+		memcpy((char *)zhent, (char *)&zhist_valent->zro_valent, SIZEOF(zro_validation_entry));
+	}
+	return lcl_recent_zhist;
 }
 
-/*
- * zro_record_zhist
- * INPUT:
- * 	routine name
- * 	$ZROUTINES entry identifier
- * OUTPUT:
- * 	cycle_addr
- * 	current value at cycle_addr
- * 	NOTE: both saved into current history entry, "zhent"
+/* Routine called from zro_search_hist() to add a $ZROUTINES entry to the (local) search history for a given object file.
+ *
+ * Parameters:
+ *   zhist_valent	- $ZROUTINES search history entry to be filled in.
+ *   obj_container	- $ZROUTINES entry for a given object directory.
+ *   rtnname		- mstr addr containing name of the routine.
+ *
  */
-void zro_record_zhist(zro_validation_entry *zhent, zro_ent *obj_container, mstr *rtnname)
+void zro_record_zhist(zro_search_hist_ent *zhist_valent, zro_ent *obj_container, mstr *rtnname)
 {
 	open_relinkctl_sgm	*linkctl;
-	relinkrec_loc_t		rec;
 	int			len;
 
 	assert(NULL != obj_container);
 	linkctl = obj_container->relinkctl_sgmaddr;
 	assert(NULL != linkctl);
-	zhent->relinkctl_bkptr = linkctl;
-	assert(NULL != zhent);
-	rec = relinkctl_insert_record(linkctl, rtnname);
-	zhent->cycle_loc = rec;
-	zhent->cycle = RELINKCTL_CYCLE_READ(linkctl, zhent->cycle_loc);
+	zhist_valent->zro_valent.relinkctl_bkptr = linkctl;
+	assert(NULL != zhist_valent);
+	assert(rtnname->len < SIZEOF(mident_fixed));
+	memcpy(zhist_valent->rtnname.c, rtnname->addr, rtnname->len);
+	zhist_valent->rtnname_len = rtnname->len;
+	if (SIZEOF(zhist_valent->rtnname) > rtnname->len)
+		memset((zhist_valent->rtnname.c + rtnname->len), '\0', SIZEOF(zhist_valent->rtnname) - rtnname->len);
 }
-#endif /* USHBIN_SUPPORTED */
+#endif /* AUTORELINK_SUPPORTED */
diff --git a/sr_unix/zhist.h b/sr_unix/zhist.h
deleted file mode 100644
index c2dc801..0000000
--- a/sr_unix/zhist.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/****************************************************************
- *								*
- *	Copyright 2013, 2014 Fidelity Information Services, Inc	*
- *								*
- *	This source code contains the intellectual property	*
- *	of its copyright holder(s), 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 ZHIST_H_INCLUDED
-#define ZHIST_H_INCLUDED
-
-#include "relinkctl.h"
-#include "zroutinessp.h"
-
-/*
- * Suppose, for example, $ZROUTINES="dir1 dir2 dir3".
- * TODO: explain validation logic............
- */
-
-typedef struct
-{
-	uint4			cycle;				/* private copy */
-	relinkrec_loc_t		cycle_loc;			/* location of record containing shared copy */
-	open_relinkctl_sgm	*relinkctl_bkptr;
-	/* backpointer to zro_ent? any reason for that? maybe debugging? */
-} zro_validation_entry;
-
-typedef struct
-{
-	uint4			zroutines_cycle;		/* compare to set_zroutines_cycle */
-	zro_validation_entry	*end;				/* end - &base[0] = size of allocated validation array */
-	zro_validation_entry	base[1];			/* base of allocated validation array */
-} zro_hist;
-
-boolean_t need_relink(rhdtyp *rtnhdr, zro_hist *zhist);
-void zro_zhist_saverecent(zro_validation_entry *zhent, zro_validation_entry *zhent_base);
-void zro_record_zhist(zro_validation_entry *zhent, zro_ent *obj_container, mstr *rtnname);
-
-#endif /* ZHIST_H_INCLUDED */
diff --git a/sr_unix/zro_gettok.c b/sr_unix/zro_gettok.c
index ad132ac..3097dcc 100644
--- a/sr_unix/zro_gettok.c
+++ b/sr_unix/zro_gettok.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2007 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -10,6 +10,9 @@
  ****************************************************************/
 
 #include "mdef.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h"
+#endif
 #include "zroutines.h"
 
 int zro_gettok (char **lp, char *top, mstr *tok)
@@ -19,29 +22,29 @@ int zro_gettok (char **lp, char *top, mstr *tok)
 	if (*lp >= top)
 		toktyp = ZRO_EOL;
 	else
-	switch (**lp)
-	{
-	case ZRO_DEL:
+		switch (**lp)
+		{
+			case ZRO_DEL:
 
-		toktyp = ZRO_DEL;
-		while (*lp < top && **lp == ZRO_DEL)
-			(*lp)++;
-		break;
-	case ZRO_LBR:
-		toktyp = ZRO_LBR;
-		(*lp)++;
-		break;
-	case ZRO_RBR:
-		toktyp = ZRO_RBR;
-		(*lp)++;
-		break;
-	default:
-		tok->addr = *lp;
-		while (*lp < top && **lp != ZRO_DEL && **lp != ZRO_LBR && **lp != ZRO_RBR)
-			(*lp)++;
-		toktyp = ZRO_IDN;
-		tok->len = INTCAST(*lp - tok->addr);
-		break;
-	}
+				toktyp = ZRO_DEL;
+				while (*lp < top && **lp == ZRO_DEL)
+					(*lp)++;
+				break;
+			case ZRO_LBR:
+				toktyp = ZRO_LBR;
+				(*lp)++;
+				break;
+			case ZRO_RBR:
+				toktyp = ZRO_RBR;
+				(*lp)++;
+				break;
+			default:
+				tok->addr = *lp;
+				while (*lp < top && **lp != ZRO_DEL && **lp != ZRO_LBR && **lp != ZRO_RBR)
+					(*lp)++;
+				toktyp = ZRO_IDN;
+				tok->len = INTCAST(*lp - tok->addr);
+				break;
+		}
 	return toktyp;
 }
diff --git a/sr_unix/zro_load.c b/sr_unix/zro_load.c
index 85cd19b..43e38cf 100644
--- a/sr_unix/zro_load.c
+++ b/sr_unix/zro_load.c
@@ -23,7 +23,6 @@
 #include "eintr_wrappers.h"
 #include "error.h"
 #include "zro_shlibs.h"
-#include "zhist.h"
 #include "gtm_limits.h"
 
 #define GETTOK		zro_gettok(&lp, top, &tok)
@@ -62,6 +61,7 @@ void zro_load(mstr *str)
 
 	SETUP_THREADGBL_ACCESS;
 	(TREF(set_zroutines_cycle))++;		/* Signal need to recompute zroutines histories for each linked routine */
+	ARLINK_ONLY(TREF(arlink_enabled) = FALSE);	/* Set if any zro entry is enabled for autorelink */
 	memset(array, 0, SIZEOF(array));
 	lp = str->addr;
 	top = lp + str->len;
@@ -73,7 +73,7 @@ void zro_load(mstr *str)
 	pblk.buffer = tranbuf;
 	toktyp = GETTOK;
 	if (ZRO_EOL == toktyp)
-	{	/* Null string - set default */
+	{	/* Null string - set default - implies current working directory only */
 		array[0].count = 1;
 		array[1].type = ZRO_TYPE_OBJECT;
 		array[1].str.len = 0;
@@ -96,18 +96,18 @@ void zro_load(mstr *str)
 			 * user desires this directory to have auto-relink capability.
 			 */
 			enable_autorelink = FALSE;
-#			ifdef USHBIN_SUPPORTED
-			/* Only shared binary platforms recognize the auto-relink indicator. Specifying "*" at end of other
-			 * directories causes an error further downstream (FILEPARSE) when the "*" is not stipped off the file
-			 * name - unless someone has managed to create a directory with a "*" suffix.
+			/* All platforms allow the auto-relink indicator on object directories but only autorelink able platforms
+			 * (#ifdef AUTORELINK_SUPPORTED is set) do anything with it. Other platforms just ignore it. Specifying
+			 * "*" at end of non-object directories causes an error further downstream (FILEPARSE) when the "*" is
+			 * not stripped off the file name - unless someone has managed to create a directory with a "*" suffix.
 			 */
 			if (ZRO_ALF == *(tok.addr + tok.len - 1))
 			{	/* Auto-relink is indicated */
 				enable_autorelink = TRUE;
+				TREF(arlink_enabled) = TRUE;
 				--tok.len;		/* Remove indicator from name so we can use it */
 				assert(0 <= tok.len);
 			}
-#			endif
 			if (SIZEOF(tranbuf) <= tok.len)
 				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
 					      ERR_FILEPARSE, 2, tok.len, tok.addr);
@@ -140,7 +140,17 @@ void zro_load(mstr *str)
 				array[oi].type = ZRO_TYPE_OBJECT;
 				array[oi + 1].type = ZRO_TYPE_COUNT;
 				si = oi + 2;
-#				ifdef USHBIN_SUPPORTED
+#				ifdef AUTORELINK_SUPPORTED
+#					ifdef DEBUG
+					/* If env var gtm_test_autorelink_always is set in dbg version, treat every
+					 * object directory specified in $zroutines as if * has been additionally specified.
+					 */
+					if (TREF(gtm_test_autorelink_always))
+					{
+						enable_autorelink = TRUE;
+						TREF(arlink_enabled) = TRUE;
+					}
+#					endif
 				if (enable_autorelink)
 				{	/* Only setup autorelink struct if it is enabled */
 					transtr.addr = tranbuf;
@@ -228,8 +238,8 @@ void zro_load(mstr *str)
 		assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
 		oi = (TREF(zro_root))->count;
 		assert(oi);
-		for (op = TREF(zro_root) + 1; oi-- > 0; )
-		{	/* release space held by translated entries */
+		for (op = TREF(zro_root) + 1; 0 < oi--;)
+		{	/* Release space held by translated entries */
 			assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
 			if (op->str.len)
 				free(op->str.addr);
@@ -237,7 +247,7 @@ void zro_load(mstr *str)
 				continue;	/* i.e. no sources for shared library */
 			assert(ZRO_TYPE_COUNT == op->type);
 			si = (op++)->count;
-			for ( ; si-- > 0; op++)
+			for (; si-- > 0; op++)
 			{
 				assert(ZRO_TYPE_SOURCE == op->type);
 				if (op->str.len)
@@ -248,10 +258,10 @@ void zro_load(mstr *str)
 	}
 	TREF(zro_root) = (zro_ent *)malloc(total_ents * SIZEOF(zro_ent));
 	memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, total_ents * SIZEOF(zro_ent));
-	assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
+	assert(ZRO_TYPE_COUNT == (TREF(zro_root))->type);
 	oi = (TREF(zro_root))->count;
 	assert(oi);
-	for (op = TREF(zro_root) + 1; oi-- > 0; )
+	for (op = TREF(zro_root) + 1; 0 < oi--;)
 	{
 		assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
 		if (op->str.len)
@@ -270,7 +280,7 @@ void zro_load(mstr *str)
 			continue;
 		assert(ZRO_TYPE_COUNT == op->type);
 		si = (op++)->count;
-		for ( ; si-- > 0; op++)
+		for (; 0 < si--; op++)
 		{
 			assert(ZRO_TYPE_SOURCE == op->type);
 			if (op->str.len)
diff --git a/sr_unix/zro_search.c b/sr_unix/zro_search.c
index a8690f6..3ada824 100644
--- a/sr_unix/zro_search.c
+++ b/sr_unix/zro_search.c
@@ -16,68 +16,94 @@
 #include "gtm_limits.h"
 #include <errno.h>
 
-#include "zroutines.h"
 #include "eintr_wrappers.h"
 #include "error.h"
-#include "lv_val.h"	/* needed for "fgncal.h" */
+#include "lv_val.h"		/* Needed for "fgncal.h" */
 #include "fgncal.h"
 #include "min_max.h"
-#ifdef USHBIN_SUPPORTED
-#include <rtnhdr.h>	/* needed for "zhist.h" */
-#include "zhist.h"
+#ifdef AUTORELINK_SUPPORTED
+# include "rtnhdr.h"		/* Defines zro_hist * type for return */
+# include "parse_file.h"	/* Needed for zro_search_hist() */
+#endif
+#ifdef DEBUG
+#include "toktyp.h"		/* Needed for "valid_mname.h" */
+#include "valid_mname.h"
 #endif
+#include "zroutines.h"
+#include "arlinkdbg.h"
 
-error_def	(ERR_ZFILENMTOOLONG);
-error_def	(ERR_SYSCALL);
+error_def(ERR_FILEPARSE);
+error_def(ERR_SYSCALL);
+error_def(ERR_WILDCARD);
+error_def(ERR_ZFILENMTOOLONG);
+error_def(ERR_ZLINKFILE);
 
-/* TODO: description
- * mstr		*objstr;	If NULL, do not search for object, else pointer to object file text string.
- * zro_ent	**objdir;	NULL if objstr is NULL, otherwise, return pointer to associated object directory.
- *				Note objdir is NULL if object directory is not found.
- * mstr		*srcstr;	Like objstr, except for associated source program.
- * zro_ent	**srcdir;	Like objdir, except for associated source program directory.
- * boolean_t	skip;		If TRUE, skip over shared libraries. If FALSE, probe shared libraries.
+/* Routine to perform a search of the $ZROUTINES structures (zro_ent) for a given routine source and/or object.
+ *
+ * Run through the zro_ent structures (source and/or object depending on which args have values). If looking for
+ * both, find a related pair (i.e. we don't find objects for unrelated sources or vice versa). The zro_ent
+ * structure list is in the following format:
+ *   a. An object directory (which itself can be the source directory too if no source directories explicitly
+ *      specified - example a zro_ent such as "obj(src)" has one object and one source dir where a spec such as
+ *      "dir" is both an object and source directory).
+ *   b. 0 or more related source directories
+ * This then repeats until the end of the list (the ZRO_TYPE_COUNT records tell how many records exist of the given
+ * type).
+ *
+ * Parameters:
+ *   objstr	- If NULL, do not search for object, else pointer to object file text string.
+ *   objdir	- NULL if objstr is NULL, otherwise is return pointer to associated object directory
+ *		  (Note objdir is set to NULL if object directory is not found).
+ *   srcstr	- Like objstr, except for associated source program.
+ *   srcdir	- Like objdir, except for associated source program directory.
+ *   skip_shlib	- If TRUE, skip over shared libraries. If FALSE, probe shared libraries.
+ *
+ * No return value.
  */
-void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip)
+void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip_shlib)
 {
-	uint4	status;
-	zro_ent		*op, *sp, *op_result, *sp_result;
-	char		objfn[PATH_MAX], srcfn[PATH_MAX], *obp, *sbp;
-	int		objcnt, srccnt;
-	struct  stat	outbuf;
-	int		stat_res;
-	mstr		rtnname;
-#	ifdef USHBIN_SUPPORTED
-	zro_validation_entry	zhent_base[ZRO_MAX_ENTS];
-	zro_validation_entry	*zhent;
-#	endif
+	uint4			status;
+	zro_ent			*op, *sp, *op_result, *sp_result;
+	char			objfn[PATH_MAX], srcfn[PATH_MAX], *obp, *sbp, save_char;
+	int			objcnt, srccnt;
+	struct stat		outbuf;
+	int			stat_res;
+	mstr			rtnname;
 	DCL_THREADGBL_ACCESS;
 
 	SETUP_THREADGBL_ACCESS;
 	if (!TREF(zro_root))
 		zro_init();
-	assert(objstr || srcstr);	/* must search for object or source or both */
-	assert(!objstr || objdir);	/* if object text, then must have pointer for result */
-	assert(!srcstr || srcdir);	/* if source text, then must have pointer for result */
+	assert((NULL != objstr) || (NULL != srcstr));	/* Must search for object or source or both */
+	assert((NULL == objstr) || (NULL != objdir));	/* If object text, then must have pointer for result */
+	assert((NULL == srcstr) || (NULL != srcdir));	/* If source text, then must have pointer for result */
 	assert(ZRO_TYPE_COUNT == (TREF(zro_root))->type);
 	op_result = sp_result = NULL;
 	objcnt = (TREF(zro_root))->count;
-	assert(objcnt);
-	USHBIN_ONLY(zhent = &zhent_base[0]);
+	assert(0 < objcnt);
 	for (op = TREF(zro_root) + 1; !op_result && !sp_result && (0 < objcnt--); )
 	{
 		assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
-		if (objstr)
+		if (NULL != objstr)
 		{
 			if (ZRO_TYPE_OBJLIB == op->type)
 			{
-				if (!skip)
+				if (!skip_shlib)
 				{
 					assert(op->shrlib);
 					rtnname.len = objstr->len - (int)STR_LIT_LEN(DOTOBJ);
 					memcpy(objfn, objstr->addr, rtnname.len);
 					objfn[rtnname.len] = 0;
 					rtnname.addr = objfn;
+#					ifdef DEBUG
+					save_char = rtnname.addr[0];
+					if ('_' == save_char)
+						rtnname.addr[0] = '%';
+							/* Temporary adjustment for "valid_mname" to not assert fail */
+					assert(valid_mname(&rtnname));
+					if ('_' == save_char)
+						rtnname.addr[0] = save_char;	/* restore */
+#					endif
 					if (NULL != (op->shrsym = (void *)fgn_getrtn(op->shrlib, &rtnname, SUCCESS)))
 						/* Note assignment above */
 						op_result = op;
@@ -105,31 +131,20 @@ void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir,
 						      errno);
 			} else
 				op_result = op;
-#			ifdef USHBIN_SUPPORTED
-			if ((NULL != op) && (NULL != op->relinkctl_sgmaddr))
-			{	/* If this directory is auto-relink enabled, make sure to track the usages */
-				rtnname.len = MIN(objstr->len - (int)STR_LIT_LEN(DOTOBJ), MAX_MIDENT_LEN);
-				memcpy(objfn, objstr->addr, rtnname.len);
-				objfn[rtnname.len] = '\0';
-				rtnname.addr = objfn;
-				zro_record_zhist(zhent++, op, &rtnname);
-			}
-#			endif
 		}
 		if (srcstr)
 		{
 			sp = op + 1;
 			if (ZRO_TYPE_OBJLIB == op->type)
 			{
-				op = sp;
-				continue;
+				op = sp;				continue;
 			}
 			assert(ZRO_TYPE_COUNT == sp->type);
 			srccnt = (sp++)->count;
 			for ( ; !sp_result && srccnt-- > 0; sp++)
 			{
 				assert(sp->type == ZRO_TYPE_SOURCE);
-				if (sp->str.len + srcstr->len + 2 > SIZEOF(srcfn)) /* extra 2 for '/' & null */
+				if (sp->str.len + srcstr->len + 2 > SIZEOF(srcfn)) /* Extra 2 for '/' & null */
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, sp->str.len, sp->str.addr);
 				sbp = &srcfn[0];
 				if (sp->str.len)
@@ -162,19 +177,121 @@ void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir,
 			op++;
 		}
 	}
-#	ifdef USHBIN_SUPPORTED
-	if ((NULL != op_result) && (NULL != op_result->relinkctl_sgmaddr))
-		/* If this directory is auto-relink enabled, make sure to track the usages */
-		zro_zhist_saverecent(zhent, &zhent_base[0]);
-	else
-		/* If didn't find a binary result, or we didn't find a relinkable routine, we have no "recent zhist" value
-		 * to return so just clear it.
-		 */
-		TREF(recent_zhist) = NULL;
-#	endif
-	if (objdir)
+	if (NULL != objdir)
 		*objdir = op_result;
-	if (srcdir)
+	if (NULL != srcdir)
 		*srcdir = sp_result;
 	return;
 }
+
+#ifdef AUTORELINK_SUPPORTED
+/* Routine to take a given object file path and create the autorelink search history for that object and return the zro_ent
+ * structure associated with the object file with the following caveats:
+ *   1. If the file is in a $ZROUTINES entry that is not autorelink-enabled, no history is returned.
+ *   2. Directories that are not autorelink-enabled do not show up in the history.
+ *   3. If the directory is not one that is currently in $ZROUTINES, no history is returned (special case of #2).
+ *
+ * Parameters:
+ *
+ *   objstr - Address of mstr containing full path of the object file
+ *   objdir - Store *addr of the zroutines entry addr (if non-NULL). Stores NULL if not found.
+ *
+ * Return value:
+ *
+ *   Address of search history block (if NULL, *objdir is also NULL)
+ */
+zro_hist *zro_search_hist(char *objnamebuf, zro_ent **objdir)
+{
+	uint4			status;
+	parse_blk		pblk;
+	zro_ent			*op, *op_result;
+	mstr			objstr, dirpath, rtnname, zroentname;
+	int			objcnt;
+	zro_search_hist_ent	zhent_base[ZRO_MAX_ENTS];
+	zro_search_hist_ent	*zhent;
+	zro_hist		*recent_zhist;
+	char			obj_file[MAX_FBUFF + 1];
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	objstr.addr = objnamebuf;
+	assert(NULL != objstr.addr);
+	objstr.len = STRLEN(objstr.addr);
+	assert(0 < objstr.len);
+	DBGARLNK((stderr, "/n/nzro_search_hist: Entered for %s\n", objnamebuf));
+	/* First parse our input string to isolate the directory name we will look up */
+	memset(&pblk, 0, SIZEOF(pblk));
+	pblk.buff_size = MAX_FBUFF;
+	pblk.buffer = obj_file;
+	pblk.fop = F_SYNTAXO;				/* Just a syntax parse */
+	status = parse_file(&objstr, &pblk);
+	if (!(status & 1))
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, objstr.len, objstr.addr, status);
+	if (pblk.fnb & F_WILD)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ZLINKFILE, 2, objstr.len, objstr.addr,
+			      ERR_WILDCARD, 2, objstr.len, objstr.addr);
+	dirpath.len = pblk.b_dir;			/* Create mstr describing the object file's dirpath */
+	dirpath.addr = pblk.l_dir;
+	/* Remove any trailing '/' in the directory name since the directories in the zro_ent blocks have none
+	 * so we need to match their style. Note this means if for whatever unfathomable reason there is a
+	 * zro_ent for the root directory, the length can be zero so allow for that.
+	 */
+	if ('/' == *(dirpath.addr + dirpath.len - 1))
+		dirpath.len--;
+	assert((0 <= dirpath.len) && (NULL != dirpath.addr));
+	/* Build the routine-name mstr that contains only the routine name */
+	rtnname.addr = pblk.l_name;
+	rtnname.len = pblk.b_name;
+	assert((0 < rtnname.len) && (NULL != rtnname.addr));
+	CONVERT_FILENAME_TO_RTNNAME(rtnname);
+	assert(valid_mname(&rtnname));
+	DBGARLNK((stderr, "zro_search_hist: Looking for dir %.*s for routine %.*s\n", dirpath.len, dirpath.addr,
+		  rtnname.len, rtnname.addr));
+	/* Now lets locate it in the parsed $ZROUTINES block list while creating some history */
+	if (!TREF(zro_root))
+		zro_init();
+	op_result = NULL;
+	objcnt = (TREF(zro_root))->count;
+	assert(0 < objcnt);
+	zhent = &zhent_base[0];				/* History initialization */
+	for (op = TREF(zro_root) + 1; (0 < objcnt--);)
+	{	/* Once through each zro_ent block in our array only looking at object directory type entries */
+		assert((ZRO_TYPE_OBJECT == op->type) || (ZRO_TYPE_OBJLIB == op->type));
+		if (ZRO_TYPE_OBJLIB == op->type)
+			continue;			/* We only deal with object directories in this loop */
+		/* If this directory is autorelink enabled, add it to the history */
+		if (NULL != op->relinkctl_sgmaddr)
+			zro_record_zhist(zhent++, op, &rtnname);
+		/* In order to properly match the entries, we need to normalize them. The zro_ent name may or may not
+		 * have a trailing '/' in the name. The dirpath value won't have a trailing '/'.
+		 */
+		zroentname = op->str;
+		DBGARLNK((stderr, "zro_search_hist: recsleft: %d  current dirblk: %.*s\n", objcnt, zroentname.len,
+			  zroentname.addr));
+		if ((0 < zroentname.len) && ('/' == *(zroentname.addr + zroentname.len - 1)))
+			zroentname.len--;
+		if (MSTR_EQ(&dirpath, &zroentname))
+		{
+			op_result = op;
+			break;
+		}
+		/* Bump past source entries to next object entry */
+		op++;
+		assert(ZRO_TYPE_COUNT == op->type);
+		op += op->count;
+		op++;
+	}
+	if (NULL != objdir)
+		*objdir = op_result;
+	/* If either of we didn't find the directory in the $ZROUTINES list (so it couldn't be auto-relink enabled or
+	 * we found the directory but it wasn't auto-relink enabled, we need return no history or zro_ent value.
+	 */
+	if ((NULL == op_result) || (NULL == op_result->relinkctl_sgmaddr))
+		return NULL;
+	/* We found the routine in an auto-relink enabled directory so create/return the history and the zro_ent
+	 * structure we found it in.
+	 */
+	recent_zhist = zro_zhist_saverecent(zhent, &zhent_base[0]);
+	return recent_zhist;
+}
+#endif
diff --git a/sr_unix/zroutinessp.h b/sr_unix/zroutinessp.h
index 474e06b..213f0dd 100644
--- a/sr_unix/zroutinessp.h
+++ b/sr_unix/zroutinessp.h
@@ -32,7 +32,7 @@ typedef	struct zro_ent_type
 {
 	uint4		type;
 	uint4		count;
-	mstr		str;			/* Path name; str.addr is malloc'd TODO: why malloc'd?*/
+	mstr		str;			/* Path name */
 	void_ptr_t	shrlib; 		/* Result of dlopen(), if a shared library */
 	void_ptr_t	shrsym; 		/* Placeholder for result of fgn_getrtn(), which we pass from zro_search() to
 						 * incr_link().
@@ -43,5 +43,8 @@ typedef	struct zro_ent_type
 int zro_gettok(char **lp, char *top, mstr *tok);
 void zsrch_clr(int indx);
 void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir, boolean_t skip);
+#ifdef AUTORELINK_SUPPORTED
+zro_hist *zro_search_hist(char *objnamebuf, zro_ent **objdir);
+#endif
 
 #endif /* ZROUTINESSP_H_INCLUDED */
diff --git a/sr_unix/zshow_devices.c b/sr_unix/zshow_devices.c
index f2d315e..3c13138 100644
--- a/sr_unix/zshow_devices.c
+++ b/sr_unix/zshow_devices.c
@@ -60,8 +60,10 @@ LITREF zshow_index	zshow_param_index[];
 void zshow_devices(zshow_out *output)
 {
 	io_log_name	*l;		/* logical name pointer		*/
+	io_log_name	*savel;		/* logical name pointer		*/
 	mval		v;
 	mval		m;
+	io_desc 	*tiod;
 	d_rm_struct	*rm_ptr;
 	d_tt_struct	*tt_ptr;
 	d_socket_struct *dsocketptr;
@@ -94,6 +96,7 @@ void zshow_devices(zshow_out *output)
 	static readonly char devop[] = "OPEN ";
 	static readonly char devcl[] = "CLOSED ";
 	static readonly char interrupt_text[] = "ZINTERRUPT ";
+	static readonly char stdout_text[] =  "0-out";
 
 	/* gtmsocket specific */
 	static readonly char at_text[] = {'@'};
@@ -116,6 +119,7 @@ void zshow_devices(zshow_out *output)
 	static readonly char port_text[] = "PORT=";
 	static readonly char ichset_text[] = "ICHSET=";
 	static readonly char ochset_text[] = "OCHSET=";
+	static readonly char tls_text[] = "TLS ";
 #ifdef __MVS__
 	static readonly char filetag_text[] = "FILETAG=";
 	static readonly char untagged_text[] = "UNTAGGED";
@@ -135,589 +139,636 @@ void zshow_devices(zshow_out *output)
 	char	*charptr;
 
 	v.mvtype = MV_STR;
-	for (l = io_root_log_name;  l != 0;  l = l->next)
+	savel = NULL;
+	for (l = io_root_log_name;  ((l != 0) || (NULL != savel));  l = l->next)
 	{
+		/* If savel is set then process the output side of $principal */
+		if (NULL != savel)
+		{
+			l = savel;
+		}
 		if (l->iod->trans_name == l)
 		{
 			/* if it is an rm type we don't want to output the device if it is the stderr
 			   device for a pipe device */
 			if ((rm_ptr = (d_rm_struct*)l->iod->dev_sp) && rm == l->iod->type && rm_ptr->pipe && rm_ptr->stderr_parent)
 				continue;
-			v.str.addr = &l->dollar_io[0];
-			v.str.len = l->len;
-			zshow_output(output,&v.str);
+
+			if (l->iod->pair.in != l->iod->pair.out)
+			{
+				/* process the output side of $principal if savel is set */
+				if (NULL != savel)
+				{
+					tiod = l->iod->pair.out;
+					savel = NULL;
+					rm_ptr = (d_rm_struct*)tiod->dev_sp;
+					if ('&' == tiod->trans_name->dollar_io[0])
+					{
+						/* replace & with 0-out */
+						ZS_STR_OUT(&v, stdout_text);
+					} else
+					{
+						/* prepend with 0-out and a space */
+						ZS_STR_OUT(&v, stdout_text);
+						ZS_ONE_OUT(&v, space_text);
+						v.str.addr = &tiod->trans_name->dollar_io[0];
+						v.str.len = tiod->trans_name->len;
+						zshow_output(output,&v.str);
+					}
+				} else
+				{
+					/* plan to process the output side of $principal if it is std out*/
+
+					if (l->iod->pair.out == io_std_device->out)
+						savel = l;
+					tiod = l->iod;
+					v.str.addr = &l->dollar_io[0];
+					v.str.len = l->len;
+					zshow_output(output,&v.str);
+				}
+			} else
+			{
+				tiod = l->iod;
+				v.str.addr = &l->dollar_io[0];
+				v.str.len = l->len;
+				zshow_output(output,&v.str);
+			}
 			ZS_ONE_OUT(&v, space_text);
-			if (l->iod->state == dev_open)
+			if (tiod->state == dev_open)
 			{
 				ZS_STR_OUT(&v, devop);
-				switch(l->iod->type)
+				switch(tiod->type)
 				{
-					case tt:
-						ZS_STR_OUT(&v, terminal_text);
-						tt_ptr = (d_tt_struct*)l->iod->dev_sp;
-						if (!ctrlc_on && io_std_device->out == l->iod) /* and standard input */
-						{	ZS_PARM_SP(&v, zshow_nocene);
-						}
-						if (tt_ptr->enbld_outofbands.mask)
-						{	ZS_PARM_EQU(&v, zshow_ctra);
-							ZS_STR_OUT(&v,dollarc_text);
-							first = TRUE;
-							for ( i = 1, j = 0; j < 32  ; j++,i = i * 2)
-							{	if (i & tt_ptr->enbld_outofbands.mask)
-								{	if (!first)
-									{	ZS_ONE_OUT(&v, comma_text);
-									}else
-									{	first = FALSE;
-									}
-									MV_FORCE_MVAL(&m,j);
-									mval_write(output,&m,FALSE);
+				case tt:
+					ZS_STR_OUT(&v, terminal_text);
+					tt_ptr = (d_tt_struct*)tiod->dev_sp;
+					if (!ctrlc_on && io_std_device->out == tiod) /* and standard input */
+					{	ZS_PARM_SP(&v, zshow_nocene);
+					}
+					if (tt_ptr->enbld_outofbands.mask)
+					{	ZS_PARM_EQU(&v, zshow_ctra);
+						ZS_STR_OUT(&v,dollarc_text);
+						first = TRUE;
+						for ( i = 1, j = 0; j < 32  ; j++,i = i * 2)
+						{	if (i & tt_ptr->enbld_outofbands.mask)
+							{	if (!first)
+								{	ZS_ONE_OUT(&v, comma_text);
+								}else
+								{	first = FALSE;
 								}
+								MV_FORCE_MVAL(&m,j);
+								mval_write(output,&m,FALSE);
 							}
-							ZS_ONE_OUT(&v, rparen_text);
-							ZS_ONE_OUT(&v, space_text);
-						}
-						if ((int4)(tt_ptr->term_ctrl) & TRM_NOECHO)
-						{
-							ZS_PARM_SP(&v, zshow_noecho);
-						}
-						if (tt_ptr->term_ctrl & TRM_PASTHRU)
-						{
-							ZS_PARM_SP(&v, zshow_past);
-						} else
-						{
-							ZS_PARM_SP(&v, zshow_nopast);
-						}
-						if (!(tt_ptr->term_ctrl & TRM_ESCAPE))
-						{
-							ZS_PARM_SP(&v, zshow_noesca);
-						}
-						if (tt_ptr->term_ctrl & TRM_READSYNC)
-						{
-							ZS_PARM_SP(&v, zshow_reads);
-						} else
-						{
-							ZS_PARM_SP(&v, zshow_noreads);
 						}
-						if (tt_ptr->term_ctrl & TRM_NOTYPEAHD)
-						{
-							ZS_PARM_SP(&v, zshow_notype);
-						} else
-						{
-							ZS_PARM_SP(&v, zshow_type);
-						}
-						if (!l->iod->wrap)
-						{
-							ZS_PARM_SP(&v, zshow_nowrap);
-						}
-						mask_out = &tt_ptr->mask_term;
-						if (!tt_ptr->default_mask_term)
+						ZS_ONE_OUT(&v, rparen_text);
+						ZS_ONE_OUT(&v, space_text);
+					}
+					if ((int4)(tt_ptr->term_ctrl) & TRM_NOECHO)
+					{
+						ZS_PARM_SP(&v, zshow_noecho);
+					}
+					if (tt_ptr->term_ctrl & TRM_PASTHRU)
+					{
+						ZS_PARM_SP(&v, zshow_past);
+					} else
+					{
+						ZS_PARM_SP(&v, zshow_nopast);
+					}
+					if (!(tt_ptr->term_ctrl & TRM_ESCAPE))
+					{
+						ZS_PARM_SP(&v, zshow_noesca);
+					}
+					if (tt_ptr->term_ctrl & TRM_READSYNC)
+					{
+						ZS_PARM_SP(&v, zshow_reads);
+					} else
+					{
+						ZS_PARM_SP(&v, zshow_noreads);
+					}
+					if (tt_ptr->term_ctrl & TRM_NOTYPEAHD)
+					{
+						ZS_PARM_SP(&v, zshow_notype);
+					} else
+					{
+						ZS_PARM_SP(&v, zshow_type);
+					}
+					if (!tiod->wrap)
+					{
+						ZS_PARM_SP(&v, zshow_nowrap);
+					}
+					mask_out = &tt_ptr->mask_term;
+					if (!tt_ptr->default_mask_term)
+					{
+						ZS_PARM_EQU(&v, zshow_term);
+						ZS_STR_OUT(&v,dollarc_text);
+						first = TRUE;
+						for ( i = 0; i < 8 ;i++)
 						{
-							ZS_PARM_EQU(&v, zshow_term);
-							ZS_STR_OUT(&v,dollarc_text);
-							first = TRUE;
-							for ( i = 0; i < 8 ;i++)
-							{
-								for ( j = 0; j < 32; j++)
-									if (mask_out->mask[i] & (1 << j))
+							for ( j = 0; j < 32; j++)
+								if (mask_out->mask[i] & (1 << j))
+								{
+									if (!first)
 									{
-										if (!first)
-										{
-											ZS_ONE_OUT(&v, comma_text);
-										} else
-											first = FALSE;
-										MV_FORCE_MVAL(&m,i * 32 + j);
-										mval_write(output,&m,FALSE);
-									}
-							}
-							ZS_ONE_OUT(&v, rparen_text);
-							ZS_ONE_OUT(&v, space_text);
+										ZS_ONE_OUT(&v, comma_text);
+									} else
+										first = FALSE;
+									MV_FORCE_MVAL(&m,i * 32 + j);
+									mval_write(output,&m,FALSE);
+								}
 						}
-						ZS_PARM_EQU(&v, zshow_width);
-						MV_FORCE_MVAL(&m,(int)l->iod->width);
-						mval_write(output, &m, FALSE);
+						ZS_ONE_OUT(&v, rparen_text);
 						ZS_ONE_OUT(&v, space_text);
-						ZS_PARM_EQU(&v, zshow_leng);
-						MV_FORCE_MVAL(&m,(int)l->iod->pair.out->length);
-						mval_write(output, &m, FALSE);
-						ZS_ONE_OUT(&v, space_text);
-						if (l->iod->write_filter)
-						{
-							bool twoparms = FALSE;
+					}
+					ZS_PARM_EQU(&v, zshow_width);
+					MV_FORCE_MVAL(&m,(int)tiod->width);
+					mval_write(output, &m, FALSE);
+					ZS_ONE_OUT(&v, space_text);
+					ZS_PARM_EQU(&v, zshow_leng);
+					MV_FORCE_MVAL(&m,(int)tiod->pair.out->length);
+					mval_write(output, &m, FALSE);
+					ZS_ONE_OUT(&v, space_text);
+					if (tiod->write_filter)
+					{
+						bool twoparms = FALSE;
 
-							ZS_PARM_EQU(&v, zshow_fil);
-							if (l->iod->write_filter & CHAR_FILTER)
+						ZS_PARM_EQU(&v, zshow_fil);
+						if (tiod->write_filter & CHAR_FILTER)
+						{
+							if (tiod->write_filter & ESC1)
 							{
-								if (l->iod->write_filter & ESC1)
-								{
-									twoparms = TRUE;
-									ZS_ONE_OUT(&v,lparen_text);
-								}
-								ZS_STR_OUT(&v,filchar_text);
-								if (twoparms)
-								{
-									ZS_ONE_OUT(&v, comma_text);
-									ZS_ONE_OUT(&v, space_text);
-								}
+								twoparms = TRUE;
+								ZS_ONE_OUT(&v,lparen_text);
 							}
-							if (l->iod->write_filter & ESC1)
-								ZS_STR_OUT(&v,filesc_text);
+							ZS_STR_OUT(&v,filchar_text);
 							if (twoparms)
-								ZS_ONE_OUT(&v,rparen_text);
-							ZS_ONE_OUT(&v, space_text);
+							{
+								ZS_ONE_OUT(&v, comma_text);
+								ZS_ONE_OUT(&v, space_text);
+							}
 						}
-						if (TT_EDITING & tt_ptr->ext_cap)
-							ZS_PARM_SP(&v, zshow_edit);
-						if (TT_NOINSERT & tt_ptr->ext_cap)
-							ZS_PARM_SP(&v, zshow_noinse);
-						if (TT_EMPTERM & tt_ptr->ext_cap)
-							ZS_PARM_SP(&v, zshow_empterm);
-						if (tt_ptr->canonical)
-							ZS_STR_OUT(&v, "CANONICAL ");
-						switch(l->iod->ichset)
+						if (tiod->write_filter & ESC1)
+							ZS_STR_OUT(&v,filesc_text);
+						if (twoparms)
+							ZS_ONE_OUT(&v,rparen_text);
+						ZS_ONE_OUT(&v, space_text);
+					}
+					if (TT_EDITING & tt_ptr->ext_cap)
+						ZS_PARM_SP(&v, zshow_edit);
+					if (TT_NOINSERT & tt_ptr->ext_cap)
+						ZS_PARM_SP(&v, zshow_noinse);
+					if (TT_EMPTERM & tt_ptr->ext_cap)
+						ZS_PARM_SP(&v, zshow_empterm);
+					if (tt_ptr->canonical)
+						ZS_STR_OUT(&v, "CANONICAL ");
+					switch(tiod->ichset)
+					{
+					case CHSET_M:
+						if (gtm_utf8_mode)
 						{
-							case CHSET_M:
-								if (gtm_utf8_mode)
-								{
-									ZS_STR_OUT(&v, ichset_text);
-									zshow_output(output, &chset_names[l->iod->ichset]);
-									ZS_ONE_OUT(&v, space_text);
-								}
-								break;
-							case CHSET_UTF8:
-								assert(gtm_utf8_mode);
-								break;
-							default:
-								assertpro(l->iod->ichset != l->iod->ichset);
+							ZS_STR_OUT(&v, ichset_text);
+							zshow_output(output, &chset_names[tiod->ichset]);
+							ZS_ONE_OUT(&v, space_text);
 						}
-						switch(l->iod->ochset)
+						break;
+					case CHSET_UTF8:
+						assert(gtm_utf8_mode);
+						break;
+					default:
+						assertpro(tiod->ichset != tiod->ichset);
+					}
+					switch(tiod->ochset)
+					{
+					case CHSET_M:
+						if (gtm_utf8_mode)
 						{
-							case CHSET_M:
-								if (gtm_utf8_mode)
-								{
-									ZS_STR_OUT(&v, ochset_text);
-									zshow_output(output, &chset_names[l->iod->ochset]);
-									ZS_ONE_OUT(&v, space_text);
-								}
-								break;
-							case CHSET_UTF8:
-								assert(gtm_utf8_mode);
-								break;
-							default:
-								assertpro(l->iod->ochset != l->iod->ochset);
+							ZS_STR_OUT(&v, ochset_text);
+							zshow_output(output, &chset_names[tiod->ochset]);
+							ZS_ONE_OUT(&v, space_text);
 						}
-						if (tt_ptr->mupintr)
-							ZS_STR_OUT(&v, interrupt_text);
 						break;
-					case rm:
-						/* we go to rm_ptr above for the rm type */
+					case CHSET_UTF8:
+						assert(gtm_utf8_mode);
+						break;
+					default:
+						assertpro(tiod->ochset != tiod->ochset);
+					}
+					if (tt_ptr->mupintr)
+						ZS_STR_OUT(&v, interrupt_text);
+					break;
+				case rm:
+					/* we go to rm_ptr above for the rm type */
 
-						if (rm_ptr->fifo)
-							ZS_STR_OUT(&v,fifo_text);
-						else if (!rm_ptr->pipe)
+					if (rm_ptr->fifo)
+						ZS_STR_OUT(&v,fifo_text);
+					else if (!rm_ptr->pipe)
+					{
+						ZS_STR_OUT(&v,rmsfile_text);
+						if (rm_ptr->follow)
 						{
-							ZS_STR_OUT(&v,rmsfile_text);
-							if (rm_ptr->follow)
-							{
-								ZS_PARM_SP(&v, zshow_follow);
-							}
+							ZS_PARM_SP(&v, zshow_follow);
 						}
-						else
+					}
+					else
+					{
+						ZS_STR_OUT(&v,pipe_text);
+						if (rm_ptr->dev_param_pairs.num_pairs)
 						{
-							ZS_STR_OUT(&v,pipe_text);
-							if (rm_ptr->dev_param_pairs.num_pairs)
-							{
-								int ignore_stderr = FALSE;
-								/* if one of the dev_param_pairs[i]->name is the
-								   STDERR then we don't want to output it if the
-								   device is closed.  We'll check them all even though
-								   it is currently the last one - just to be safe. */
-								if (rm_ptr->stderr_child && (dev_open !=
-											     rm_ptr->stderr_child->state))
-									ignore_stderr = TRUE;
+							int ignore_stderr = FALSE;
+							/* if one of the dev_param_pairs[i]->name is the
+							   STDERR then we don't want to output it if the
+							   device is closed.  We'll check them all even though
+							   it is currently the last one - just to be safe. */
+							if (rm_ptr->stderr_child && (dev_open !=
+										     rm_ptr->stderr_child->state))
+								ignore_stderr = TRUE;
 
-								for ( i = 0; i < rm_ptr->dev_param_pairs.num_pairs; i++ )
-								{
-									if (TRUE == ignore_stderr &&
-									    0 == STRCMP(rm_ptr->dev_param_pairs.pairs[i].name,
-											"STDERR="))
-										continue;
-									ZS_VAR_STR_OUT(
-										&v,rm_ptr->dev_param_pairs.pairs[i].name);
-									ZS_VAR_STR_OUT(
-										&v,rm_ptr->dev_param_pairs.pairs[i].definition);
-									ZS_ONE_OUT(&v, space_text);
-								}
-							}
-							if (rm_ptr->independent)
-							{
-								ZS_PARM_SP(&v, zshow_independent);
-							}
-							if (rm_ptr->parse)
+							for ( i = 0; i < rm_ptr->dev_param_pairs.num_pairs; i++ )
 							{
-								ZS_PARM_SP(&v, zshow_parse);
+								if (TRUE == ignore_stderr &&
+								    0 == STRCMP(rm_ptr->dev_param_pairs.pairs[i].name,
+										"STDERR="))
+									continue;
+								ZS_VAR_STR_OUT(
+									&v,rm_ptr->dev_param_pairs.pairs[i].name);
+								ZS_VAR_STR_OUT(
+									&v,rm_ptr->dev_param_pairs.pairs[i].definition);
+								ZS_ONE_OUT(&v, space_text);
 							}
 						}
-						if (rm_ptr->fixed)
+						if (rm_ptr->independent)
 						{
-							ZS_PARM_SP(&v, zshow_fixed);
+							ZS_PARM_SP(&v, zshow_independent);
 						}
-#						ifdef UNIX
-						else if (rm_ptr->stream)
+						if (rm_ptr->parse)
 						{
-							ZS_PARM_SP(&v, zshow_stream);
+							ZS_PARM_SP(&v, zshow_parse);
 						}
+					}
+					if (rm_ptr->fixed)
+					{
+						ZS_PARM_SP(&v, zshow_fixed);
+					}
+#						ifdef UNIX
+					else if (rm_ptr->stream)
+					{
+						ZS_PARM_SP(&v, zshow_stream);
+					}
 #						endif
-						if (rm_ptr->read_only)
-						{
-							ZS_PARM_SP(&v, zshow_read);
-						}
-						if (gtm_utf8_mode && (IS_UTF_CHSET(l->iod->ichset) || IS_UTF_CHSET(l->iod->ochset)))
-						{
-							if (!rm_ptr->def_recsize)
-							{
-								ZS_PARM_EQU(&v, zshow_rec);
-								MV_FORCE_MVAL(&m, (int)rm_ptr->recordsize);
-								mval_write(output, &m, FALSE);
-								ZS_ONE_OUT(&v, space_text);
-							}
-							if (!rm_ptr->def_width)
-							{
-								ZS_PARM_EQU(&v, zshow_width);
-								MV_FORCE_MVAL(&m, (int)l->iod->width);
-								mval_write(output, &m, FALSE);
-								ZS_ONE_OUT(&v, space_text);
-							}
-						}
-						else if (l->iod->width != DEF_RM_WIDTH)
+					if (rm_ptr->read_only)
+					{
+						ZS_PARM_SP(&v, zshow_read);
+					}
+					if (gtm_utf8_mode && (IS_UTF_CHSET(tiod->ichset) || IS_UTF_CHSET(tiod->ochset)))
+					{
+						if (!rm_ptr->def_recsize)
 						{
 							ZS_PARM_EQU(&v, zshow_rec);
-							MV_FORCE_MVAL(&m,(int)l->iod->width);
+							MV_FORCE_MVAL(&m, (int)rm_ptr->recordsize);
 							mval_write(output, &m, FALSE);
 							ZS_ONE_OUT(&v, space_text);
 						}
-						if (!l->iod->wrap)
+						if (!rm_ptr->def_width)
 						{
-							ZS_PARM_SP(&v, zshow_nowrap);
+							ZS_PARM_EQU(&v, zshow_width);
+							MV_FORCE_MVAL(&m, (int)tiod->width);
+							mval_write(output, &m, FALSE);
+							ZS_ONE_OUT(&v, space_text);
 						}
-						switch(l->iod->ichset)
+					}
+					else if (tiod->width != DEF_RM_WIDTH)
+					{
+						ZS_PARM_EQU(&v, zshow_rec);
+						MV_FORCE_MVAL(&m,(int)tiod->width);
+						mval_write(output, &m, FALSE);
+						ZS_ONE_OUT(&v, space_text);
+					}
+					if (!tiod->wrap)
+					{
+						ZS_PARM_SP(&v, zshow_nowrap);
+					}
+					switch(tiod->ichset)
+					{
+					case CHSET_M:
+						if (gtm_utf8_mode)
 						{
-							case CHSET_M:
-								if (gtm_utf8_mode)
-								{
-									ZS_STR_OUT(&v, ichset_text);
-									zshow_output(output, &chset_names[l->iod->ichset]);
-									ZS_ONE_OUT(&v, space_text);
-								}
-								break;
-							case CHSET_UTF8:
-								assert(gtm_utf8_mode);
-								break;
-							case CHSET_UTF16:
-							case CHSET_UTF16BE:
-							case CHSET_UTF16LE:
-								assert(gtm_utf8_mode);
-								ZS_STR_OUT(&v, ichset_text);
-								zshow_output(output, &chset_names[l->iod->ichset]);
-								ZS_ONE_OUT(&v, space_text);
-								break;
-							default:
-								assertpro(l->iod->ichset != l->iod->ichset);
+							ZS_STR_OUT(&v, ichset_text);
+							zshow_output(output, &chset_names[tiod->ichset]);
+							ZS_ONE_OUT(&v, space_text);
 						}
-						switch(l->iod->ochset)
+						break;
+					case CHSET_UTF8:
+						assert(gtm_utf8_mode);
+						break;
+					case CHSET_UTF16:
+					case CHSET_UTF16BE:
+					case CHSET_UTF16LE:
+						assert(gtm_utf8_mode);
+						ZS_STR_OUT(&v, ichset_text);
+						zshow_output(output, &chset_names[tiod->ichset]);
+						ZS_ONE_OUT(&v, space_text);
+						break;
+					default:
+						assertpro(tiod->ichset != tiod->ichset);
+					}
+					switch(tiod->ochset)
+					{
+					case CHSET_M:
+						if (gtm_utf8_mode)
 						{
-							case CHSET_M:
-								if (gtm_utf8_mode)
-								{
-									ZS_STR_OUT(&v, ochset_text);
-									zshow_output(output, &chset_names[l->iod->ochset]);
-									ZS_ONE_OUT(&v, space_text);
-								}
-								break;
-							case CHSET_UTF8:
-								assert(gtm_utf8_mode);
-								break;
-							case CHSET_UTF16:
-							case CHSET_UTF16BE:
-							case CHSET_UTF16LE:
-								assert(gtm_utf8_mode);
-								ZS_STR_OUT(&v, ochset_text);
-								zshow_output(output, &chset_names[l->iod->ochset]);
-								ZS_ONE_OUT(&v, space_text);
-								break;
-							default:
-								assertpro(l->iod->ochset != l->iod->ochset);
+							ZS_STR_OUT(&v, ochset_text);
+							zshow_output(output, &chset_names[tiod->ochset]);
+							ZS_ONE_OUT(&v, space_text);
 						}
+						break;
+					case CHSET_UTF8:
+						assert(gtm_utf8_mode);
+						break;
+					case CHSET_UTF16:
+					case CHSET_UTF16BE:
+					case CHSET_UTF16LE:
+						assert(gtm_utf8_mode);
+						ZS_STR_OUT(&v, ochset_text);
+						zshow_output(output, &chset_names[tiod->ochset]);
+						ZS_ONE_OUT(&v, space_text);
+						break;
+					default:
+						assertpro(tiod->ochset != tiod->ochset);
+					}
 #ifdef __MVS__
-						if (TAG_ASCII != l->iod->file_tag)
+					if (TAG_ASCII != tiod->file_tag)
+					{
+						ZS_STR_OUT(&v, filetag_text);
+						switch ((unsigned int)tiod->file_tag)
 						{
-							ZS_STR_OUT(&v, filetag_text);
-							switch ((unsigned int)l->iod->file_tag)
-							{
-							case TAG_UNTAGGED:
-								ZS_STR_OUT(&v, untagged_text);
-								break;
-							case TAG_EBCDIC:
-								ZS_STR_OUT(&v, ebcdic_text);
-								break;
-							case TAG_BINARY:
-								ZS_STR_OUT(&v, binary_text);
-								break;
-							default:
-								if (-1 == __toCSName((__ccsid_t)l->iod->file_tag, csname))
-								{ /* no name so output number */
-									csptr = (char *)i2asc((uchar_ptr_t)csname,
-										(unsigned int)l->iod->file_tag);
-									*csptr = '\0';	/* terminate */
-								}
-								ZS_VAR_STR_OUT(&v, csname);
+						case TAG_UNTAGGED:
+							ZS_STR_OUT(&v, untagged_text);
+							break;
+						case TAG_EBCDIC:
+							ZS_STR_OUT(&v, ebcdic_text);
+							break;
+						case TAG_BINARY:
+							ZS_STR_OUT(&v, binary_text);
+							break;
+						default:
+							if (-1 == __toCSName((__ccsid_t)tiod->file_tag, csname))
+							{ /* no name so output number */
+								csptr = (char *)i2asc((uchar_ptr_t)csname,
+										      (unsigned int)tiod->file_tag);
+								*csptr = '\0';	/* terminate */
 							}
-							if (l->iod->text_flag)
-								ZS_STR_OUT(&v, text_text);
-							ZS_ONE_OUT(&v, space_text);
-						}
-						if (l->iod->file_chset != l->iod->process_chset &&
-							(!(0 == l->iod->file_chset && CHSET_ASCII == l->iod->process_chset) &&
-							 !(CHSET_ASCII == l->iod->file_chset && CHSET_M == l->iod->process_chset)))
-						{	/* suppress default cases */
-							ZS_STR_OUT(&v, processchset_text);
-							zshow_output(output, &chset_names[l->iod->process_chset]);
-							ZS_ONE_OUT(&v, space_text);
+							ZS_VAR_STR_OUT(&v, csname);
 						}
+						if (tiod->text_flag)
+							ZS_STR_OUT(&v, text_text);
+						ZS_ONE_OUT(&v, space_text);
+					}
+					if (tiod->file_chset != tiod->process_chset &&
+					    (!(0 == tiod->file_chset && CHSET_ASCII == tiod->process_chset) &&
+					     !(CHSET_ASCII == tiod->file_chset && CHSET_M == tiod->process_chset)))
+					{	/* suppress default cases */
+						ZS_STR_OUT(&v, processchset_text);
+						zshow_output(output, &chset_names[tiod->process_chset]);
+						ZS_ONE_OUT(&v, space_text);
+					}
 #endif
-						break;
-					case gtmsocket:
-						delim.addr = delim_mstr_buff;
-						delim_len = 0;
+					break;
+				case gtmsocket:
+					delim.addr = delim_mstr_buff;
+					delim_len = 0;
+					ZS_STR_OUT(&v, socket_text);
+					dsocketptr = (d_socket_struct *)tiod->dev_sp;
+					ZS_ONE_OUT(&v, space_text);
+					if (!tiod->wrap)
+					{
+						ZS_PARM_SP(&v, zshow_nowrap);
+					}
+					ZS_STR_OUT(&v, total_text);
+					MV_FORCE_MVAL(&m, (int)dsocketptr->n_socket);
+					mval_write(output, &m, FALSE);
+					ZS_ONE_OUT(&v, space_text);
+					ZS_STR_OUT(&v, current_text);
+					MV_FORCE_MVAL(&m, (int)dsocketptr->current_socket);
+					mval_write(output, &m, FALSE);
+					ZS_ONE_OUT(&v, space_text);
+					if (dsocketptr->mupintr)
+						ZS_STR_OUT(&v, interrupt_text);
+					output->flush = TRUE;
+					zshow_output(output, 0);
+					for(ii = 0; ii < dsocketptr->n_socket; ii++)
+					{
+						/* output each socket */
+						socketptr = dsocketptr->socket[ii];
+						ZS_STR_OUT(&v, space8_text);
+						/* socket handle */
 						ZS_STR_OUT(&v, socket_text);
-						dsocketptr = (d_socket_struct *)l->iod->dev_sp;
-						ZS_ONE_OUT(&v, space_text);
-						if (!l->iod->wrap)
-						{
-							ZS_PARM_SP(&v, zshow_nowrap);
-						}
-						ZS_STR_OUT(&v, total_text);
-						MV_FORCE_MVAL(&m, (int)dsocketptr->n_socket);
+						ZS_ONE_OUT(&v, lb_text);
+						MV_FORCE_MVAL(&m, ii);
 						mval_write(output, &m, FALSE);
+						ZS_ONE_OUT(&v, rb_text);
+						ZS_ONE_OUT(&v, equal_text);
+						v.str.addr = socketptr->handle;
+						v.str.len = socketptr->handle_len;
+						zshow_output(output, &v.str);
 						ZS_ONE_OUT(&v, space_text);
-						ZS_STR_OUT(&v, current_text);
-						MV_FORCE_MVAL(&m, (int)dsocketptr->current_socket);
+						/* socket descriptor */
+						ZS_STR_OUT(&v, descriptor_text);
+						MV_FORCE_MVAL(&m, socketptr->sd);
 						mval_write(output, &m, FALSE);
 						ZS_ONE_OUT(&v, space_text);
-						if (dsocketptr->mupintr)
-							ZS_STR_OUT(&v, interrupt_text);
-						output->flush = TRUE;
-						zshow_output(output, 0);
-						for(ii = 0; ii < dsocketptr->n_socket; ii++)
+						/* socket state */
+						ZS_STR_OUT(&v, zsh_socket_state[socketptr->state]);
+						ZS_ONE_OUT(&v, space_text);
+						/* socket IO mode */		switch(tiod->ichset)
 						{
-							/* output each socket */
-							socketptr = dsocketptr->socket[ii];
-							ZS_STR_OUT(&v, space8_text);
-							/* socket handle */
-							ZS_STR_OUT(&v, socket_text);
-							ZS_ONE_OUT(&v, lb_text);
-							MV_FORCE_MVAL(&m, ii);
-							mval_write(output, &m, FALSE);
-							ZS_ONE_OUT(&v, rb_text);
-							ZS_ONE_OUT(&v, equal_text);
-							v.str.addr = socketptr->handle;
-							v.str.len = socketptr->handle_len;
-							zshow_output(output, &v.str);
-							ZS_ONE_OUT(&v, space_text);
-							/* socket descriptor */
-							ZS_STR_OUT(&v, descriptor_text);
-							MV_FORCE_MVAL(&m, socketptr->sd);
-							mval_write(output, &m, FALSE);
-							ZS_ONE_OUT(&v, space_text);
-							/* socket state */
-							ZS_STR_OUT(&v, zsh_socket_state[socketptr->state]);
-							ZS_ONE_OUT(&v, space_text);
-							/* socket IO mode */		switch(l->iod->ichset)
+						case CHSET_M:
+							if (gtm_utf8_mode)
 							{
-								case CHSET_M:
-									if (gtm_utf8_mode)
-									{
-										ZS_STR_OUT(&v, ichset_text);
-										zshow_output(output, &chset_names[l->iod->ichset]);
-										ZS_ONE_OUT(&v, space_text);
-									}
-									break;
-								case CHSET_UTF8:
-									assert(gtm_utf8_mode);
-									break;
-								case CHSET_UTF16:
-								case CHSET_UTF16BE:
-								case CHSET_UTF16LE:
-									assert(gtm_utf8_mode);
-									ZS_STR_OUT(&v, ichset_text);
-									zshow_output(output, &chset_names[l->iod->ichset]);
-									ZS_ONE_OUT(&v, space_text);
-									break;
-								default:
-									assertpro(l->iod->ichset != l->iod->ichset);
+								ZS_STR_OUT(&v, ichset_text);
+								zshow_output(output, &chset_names[tiod->ichset]);
+								ZS_ONE_OUT(&v, space_text);
 							}
-							switch(l->iod->ochset)
+							break;
+						case CHSET_UTF8:
+							assert(gtm_utf8_mode);
+							break;
+						case CHSET_UTF16:
+						case CHSET_UTF16BE:
+						case CHSET_UTF16LE:
+							assert(gtm_utf8_mode);
+							ZS_STR_OUT(&v, ichset_text);
+							zshow_output(output, &chset_names[tiod->ichset]);
+							ZS_ONE_OUT(&v, space_text);
+							break;
+						default:
+							assertpro(tiod->ichset != tiod->ichset);
+						}
+						switch(tiod->ochset)
+						{
+						case CHSET_M:
+							if (gtm_utf8_mode)
 							{
-								case CHSET_M:
-									if (gtm_utf8_mode)
-									{
-										ZS_STR_OUT(&v, ochset_text);
-										zshow_output(output, &chset_names[l->iod->ochset]);
-										ZS_ONE_OUT(&v, space_text);
-									}
-									break;
-								case CHSET_UTF8:
-									assert(gtm_utf8_mode);
-									break;
-								case CHSET_UTF16:
-								case CHSET_UTF16BE:
-								case CHSET_UTF16LE:
-									assert(gtm_utf8_mode);
-									ZS_STR_OUT(&v, ochset_text);
-									zshow_output(output, &chset_names[l->iod->ochset]);
-									ZS_ONE_OUT(&v, space_text);
-									break;
-								default:
-									assertpro(l->iod->ochset != l->iod->ochset);
+								ZS_STR_OUT(&v, ochset_text);
+								zshow_output(output, &chset_names[tiod->ochset]);
+								ZS_ONE_OUT(&v, space_text);
 							}
-							/* socket type */
-							if (socketptr->passive)
+							break;
+						case CHSET_UTF8:
+							assert(gtm_utf8_mode);
+							break;
+						case CHSET_UTF16:
+						case CHSET_UTF16BE:
+						case CHSET_UTF16LE:
+							assert(gtm_utf8_mode);
+							ZS_STR_OUT(&v, ochset_text);
+							zshow_output(output, &chset_names[tiod->ochset]);
+							ZS_ONE_OUT(&v, space_text);
+							break;
+						default:
+							assertpro(tiod->ochset != tiod->ochset);
+						}
+						/* socket type */
+						if (socketptr->passive)
+						{
+							ZS_STR_OUT(&v, passive_text);
+						} else
+						{
+							ZS_STR_OUT(&v, active_text);
+						}
+						ZS_ONE_OUT(&v, space_text);
+						/* error trapping */
+						if (socketptr->ioerror)
+						{
+							ZS_STR_OUT(&v, trap_text);
+						} else
+						{
+							ZS_STR_OUT(&v, notrap_text);
+						}
+						ZS_ONE_OUT(&v, space_text);
+						/* address + port */
+						if ((socket_local != socketptr->protocol) && socketptr->passive)
+						{
+							ZS_STR_OUT(&v, port_text);
+							tmpport = (int)socketptr->local.port;
+							MV_FORCE_MVAL(&m, tmpport);
+							mval_write(output, &m, FALSE);
+						} else
+						{
+							ZS_STR_OUT(&v, remote_text);
+							if (NULL != socketptr->remote.saddr_ip)
 							{
-								ZS_STR_OUT(&v, passive_text);
+								v.str.addr = socketptr->remote.saddr_ip;
+								v.str.len = STRLEN(socketptr->remote.saddr_ip);
 							} else
 							{
-								ZS_STR_OUT(&v, active_text);
+								v.str.addr = "";
+								v.str.len = 0;
 							}
-							ZS_ONE_OUT(&v, space_text);
-							/* error trapping */
-							if (socketptr->ioerror)
-							{
-								ZS_STR_OUT(&v, trap_text);
-							} else
+							zshow_output(output, &v.str);
+							if (socket_local != socketptr->protocol)
 							{
-								ZS_STR_OUT(&v, notrap_text);
+								ZS_ONE_OUT(&v, at_text);
+								tmpport = (int)socketptr->remote.port;
+								MV_FORCE_MVAL(&m, tmpport);
+								mval_write(output, &m, FALSE);
 							}
 							ZS_ONE_OUT(&v, space_text);
-							/* address + port */
-							if ((socket_local != socketptr->protocol) && socketptr->passive)
+							if (NULL != socketptr->local.saddr_ip)
 							{
-								ZS_STR_OUT(&v, port_text);
+								ZS_STR_OUT(&v, local_text);
+								v.str.addr = socketptr->local.saddr_ip;
+								v.str.len = STRLEN(socketptr->local.saddr_ip);
+								zshow_output(output, &v.str);
+								ZS_ONE_OUT(&v, at_text);
 								tmpport = (int)socketptr->local.port;
 								MV_FORCE_MVAL(&m, tmpport);
 								mval_write(output, &m, FALSE);
-							} else
+							} else if (socket_local == socketptr->protocol)
 							{
-								ZS_STR_OUT(&v, remote_text);
-								if (NULL != socketptr->remote.saddr_ip)
-								{
-									v.str.addr = socketptr->remote.saddr_ip;
-									v.str.len = STRLEN(socketptr->remote.saddr_ip);
-								} else
-								{
-									v.str.addr = "";
-									v.str.len = 0;
-								}
-								zshow_output(output, &v.str);
-								if (socket_local != socketptr->protocol)
+								ZS_STR_OUT(&v, local_text);
+								if (NULL != socketptr->local.sa)
 								{
-									ZS_ONE_OUT(&v, at_text);
-									tmpport = (int)socketptr->remote.port;
-									MV_FORCE_MVAL(&m, tmpport);
-									mval_write(output, &m, FALSE);
-								}
-								ZS_ONE_OUT(&v, space_text);
-								if (NULL != socketptr->local.saddr_ip)
-								{
-									ZS_STR_OUT(&v, local_text);
-									v.str.addr = socketptr->local.saddr_ip;
-									v.str.len = STRLEN(socketptr->local.saddr_ip);
-									zshow_output(output, &v.str);
-									ZS_ONE_OUT(&v, at_text);
-									tmpport = (int)socketptr->local.port;
-									MV_FORCE_MVAL(&m, tmpport);
-									mval_write(output, &m, FALSE);
-								} else if (socket_local == socketptr->protocol)
-								{
-									ZS_STR_OUT(&v, local_text);
-									if (NULL != socketptr->local.sa)
-									{
-										charptr = ((struct sockaddr_un *)
-											(socketptr->local.sa))->sun_path;
-										ZS_VAR_STR_OUT(&v, charptr);
-									} else if (NULL != socketptr->remote.sa)
-									{ /* CONNECT shows remote path as LOCAL */
-										charptr = ((struct sockaddr_un *)
-											(socketptr->remote.sa))->sun_path;
-										ZS_VAR_STR_OUT(&v, charptr);
-									}
+									charptr = ((struct sockaddr_un *)
+										   (socketptr->local.sa))->sun_path;
+									ZS_VAR_STR_OUT(&v, charptr);
+								} else if (NULL != socketptr->remote.sa)
+								{ /* CONNECT shows remote path as LOCAL */
+									charptr = ((struct sockaddr_un *)
+										   (socketptr->remote.sa))->sun_path;
+									ZS_VAR_STR_OUT(&v, charptr);
 								}
 							}
-							ZS_ONE_OUT(&v, space_text);
+						}
+						ZS_ONE_OUT(&v, space_text);
+						output->flush = TRUE;
+						zshow_output(output, 0);
+						ZS_STR_OUT(&v, space8_text);
+						ZS_STR_OUT(&v, space8_text);
+						/* zdelay */
+						if (socketptr->nodelay)
+						{
+							ZS_STR_OUT(&v, znodelay_text);
+						} else
+						{
+							ZS_STR_OUT(&v, zdelay_text);
+						}
+						ZS_ONE_OUT(&v, space_text);
+						/* zbfsize */
+						ZS_STR_OUT(&v, zbfsize_text);
+						MV_FORCE_MVAL(&m, (int4)(socketptr->buffer_size));
+						mval_write(output, &m, FALSE);
+						ZS_ONE_OUT(&v, space_text);
+						/* izbfsize */
+						ZS_STR_OUT(&v, zibfsize_text);
+						MV_FORCE_MVAL(&m, socketptr->bufsiz);
+						mval_write(output, &m, FALSE);
+						ZS_ONE_OUT(&v, space_text);
+						if (socketptr->tlsenabled && (NULL != socketptr->tlssocket))
+						{
+							ZS_STR_OUT(&v, tls_text);
+						}
+						/* delimiters */
+						if (socketptr->n_delimiter > 0)
+						{
 							output->flush = TRUE;
 							zshow_output(output, 0);
 							ZS_STR_OUT(&v, space8_text);
 							ZS_STR_OUT(&v, space8_text);
-							/* zdelay */
-							if (socketptr->nodelay)
-							{
-								ZS_STR_OUT(&v, znodelay_text);
-							} else
+							ZS_STR_OUT(&v, delimiter_text);
+							for (jj = 0; jj < socketptr->n_delimiter; jj++)
 							{
-								ZS_STR_OUT(&v, zdelay_text);
+								delim_len_sm = socketptr->delimiter[jj].len;
+								memcpy(delim_buff_sm,
+								       socketptr->delimiter[jj].addr, delim_len_sm);
+								format2zwr(delim_buff_sm, delim_len_sm,
+									   (uchar_ptr_t)delim.addr, &delim_len);
+								delim.len = (unsigned short)delim_len;
+								assert(SIZEOF(delim_mstr_buff) >= delim_len);
+								zshow_output(output, &delim);
+								ZS_ONE_OUT(&v, space_text);
 							}
-							ZS_ONE_OUT(&v, space_text);
-							/* zbfsize */
-							ZS_STR_OUT(&v, zbfsize_text);
-							MV_FORCE_MVAL(&m, (int4)(socketptr->buffer_size));
-							mval_write(output, &m, FALSE);
-							ZS_ONE_OUT(&v, space_text);
-							/* izbfsize */
-							ZS_STR_OUT(&v, zibfsize_text);
-							MV_FORCE_MVAL(&m, socketptr->bufsiz);
+						} else
+						{
+							ZS_STR_OUT(&v, nodelimiter_text);
+						}
+						/* readmoretime */
+						if (DEFAULT_MOREREAD_TIMEOUT != socketptr->moreread_timeout)
+						{
+							ZS_STR_OUT(&v, morereadtime_text);
+							MV_FORCE_MVAL(&m, (int)socketptr->moreread_timeout);
 							mval_write(output, &m, FALSE);
-							ZS_ONE_OUT(&v, space_text);
-							/* delimiters */
-							if (socketptr->n_delimiter > 0)
-							{
-								output->flush = TRUE;
-								zshow_output(output, 0);
-								ZS_STR_OUT(&v, space8_text);
-								ZS_STR_OUT(&v, space8_text);
-								ZS_STR_OUT(&v, delimiter_text);
-								for (jj = 0; jj < socketptr->n_delimiter; jj++)
-								{
-									delim_len_sm = socketptr->delimiter[jj].len;
-									memcpy(delim_buff_sm,
-									       socketptr->delimiter[jj].addr, delim_len_sm);
-									format2zwr(delim_buff_sm, delim_len_sm,
-										   (uchar_ptr_t)delim.addr, &delim_len);
-									delim.len = (unsigned short)delim_len;
-									assert(SIZEOF(delim_mstr_buff) >= delim_len);
-									zshow_output(output, &delim);
-									ZS_ONE_OUT(&v, space_text);
-								}
-							} else
-							{
-								ZS_STR_OUT(&v, nodelimiter_text);
-							}
-							/* readmoretime */
-							if (DEFAULT_MOREREAD_TIMEOUT != socketptr->moreread_timeout)
-							{
-								ZS_STR_OUT(&v, morereadtime_text);
-								MV_FORCE_MVAL(&m, (int)socketptr->moreread_timeout);
-								mval_write(output, &m, FALSE);
-							}
-							output->flush = TRUE;
-							zshow_output(output, 0);
 						}
-					default:
-						v.str.len = 0;
-						break;
+						output->flush = TRUE;
+						zshow_output(output, 0);
+					}
+				default:
+					v.str.len = 0;
+					break;
 				}
-				if (l->iod->error_handler.len)
+				if (tiod->error_handler.len)
 				{
 					ZS_PARM_EQU(&v, zshow_exce);
 					ZS_ONE_OUT(&v, quote_text);
-					v.str = l->iod->error_handler;
+					v.str = tiod->error_handler;
 					zshow_output(output, &v.str);
 					output->flush = TRUE;
 					ZS_ONE_OUT(&v, quote_text);
diff --git a/sr_unix/zshow_rctldump.c b/sr_unix/zshow_rctldump.c
new file mode 100644
index 0000000..8136031
--- /dev/null
+++ b/sr_unix/zshow_rctldump.c
@@ -0,0 +1,96 @@
+/****************************************************************
+ *								*
+ *	Copyright 2014 Fidelity Information Services, Inc	*
+ *								*
+ *	This source code contains the intellectual property	*
+ *	of its copyright holder(s), and is made 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 AUTORELINK_SUPPORTED
+
+#include "gtm_string.h"
+
+#include "relinkctl.h"
+#include "util.h"
+#include "zshow.h"
+
+#define	DUMP_ONE_LINE(OUTPUT, BUFF, NBYTES)						\
+{											\
+	mstr	line;									\
+											\
+	if (NBYTES >= SIZEOF(BUFF))							\
+		NBYTES = SIZEOF(BUFF); /* Output from SNPRINTF was truncated. */	\
+	if (NULL != OUTPUT)								\
+	{	/* Caller is ZSHOW "R". Use zshow_output. */				\
+		line.len = NBYTES;							\
+		line.addr = &BUFF[0];							\
+		OUTPUT->flush = TRUE;							\
+		zshow_output(OUTPUT, &line);						\
+	} else										\
+	{	/* Caller is MUPIP RCTLDUMP. Use util_out_print. */			\
+		util_out_print("!AD", FLUSH, NBYTES, BUFF);				\
+	}										\
+}
+
+void	zshow_rctldump(zshow_out *output)
+{
+	open_relinkctl_sgm	*linkctl;
+	relinkshm_hdr_t		*shm_hdr;
+	relinkrec_t		*linkrec;
+	relinkctl_data		*hdr;
+	rtnobjshm_hdr_t		*rtnobj_shm_hdr;
+	int			i, j, recnum, n_records, nbytes;
+	char			buff[OUT_BUFF_SIZE];
+	DCL_THREADGBL_ACCESS;
+
+	SETUP_THREADGBL_ACCESS;
+	for (linkctl = TREF(open_relinkctl_list); NULL != linkctl; linkctl = linkctl->next)
+	{
+		hdr = linkctl->hdr;
+		nbytes = SNPRINTF(buff, SIZEOF(buff), "Object Directory         : %.*s",
+			linkctl->zro_entry_name.len, linkctl->zro_entry_name.addr);
+		DUMP_ONE_LINE(output, buff, nbytes);
+		nbytes = SNPRINTF(buff, SIZEOF(buff), "Relinkctl filename       : %s", linkctl->relinkctl_path);
+		DUMP_ONE_LINE(output, buff, nbytes);
+		n_records = hdr->n_records;
+		nbytes = SNPRINTF(buff, SIZEOF(buff), "# of routines            : %d", n_records);
+		DUMP_ONE_LINE(output, buff, nbytes);
+		nbytes = SNPRINTF(buff, SIZEOF(buff), "# of attached processes  : %d", hdr->nattached);
+		DUMP_ONE_LINE(output, buff, nbytes);
+		nbytes = SNPRINTF(buff, SIZEOF(buff), "Relinkctl shared memory  : shmid: %d  shmlen: 0x%llx",
+			hdr->relinkctl_shmid, hdr->relinkctl_shmlen);
+		DUMP_ONE_LINE(output, buff, nbytes);
+		shm_hdr = GET_RELINK_SHM_HDR(linkctl);
+		for (i = 0, j = 1; i < NUM_RTNOBJ_SHM_INDEX; i++)
+		{
+			rtnobj_shm_hdr = &shm_hdr->rtnobj_shmhdr[i];
+			if (INVALID_SHMID != rtnobj_shm_hdr->rtnobj_shmid)
+			{
+				nbytes = SNPRINTF(buff, SIZEOF(buff), "Rtnobj shared memory #%2.d : shmid: %u  shmlen: 0x%llx"
+					"  shmused: 0x%llx  shmfree: 0x%llx  objlen: 0x%llx",
+					j, rtnobj_shm_hdr->rtnobj_shmid, rtnobj_shm_hdr->shm_len,
+					rtnobj_shm_hdr->used_len,
+					rtnobj_shm_hdr->shm_len - rtnobj_shm_hdr->used_len,
+					rtnobj_shm_hdr->real_len);
+				DUMP_ONE_LINE(output, buff, nbytes);
+				j++;
+			}
+		}
+		for (linkrec = linkctl->rec_base, recnum = 1; recnum <= n_records; linkrec++, recnum++)
+		{
+			nbytes = SNPRINTF(buff, SIZEOF(buff), "    rec#%d: rtnname: %.*s  cycle: %d  objhash: 0x%llx"
+				"  numvers: %d  objlen: 0x%llx  shmlen: 0x%llx",
+				recnum, mid_len(&linkrec->rtnname_fixed), &linkrec->rtnname_fixed.c,
+				linkrec->cycle, linkrec->objhash, linkrec->numvers, linkrec->objLen,
+				linkrec->usedLen);
+			DUMP_ONE_LINE(output, buff, nbytes);
+		}
+	}
+}
+
+#endif
diff --git a/sr_unix_nsb/obj_code.c b/sr_unix_nsb/obj_code.c
index fce4e5c..b0c09f2 100644
--- a/sr_unix_nsb/obj_code.c
+++ b/sr_unix_nsb/obj_code.c
@@ -49,7 +49,9 @@ GBLREF char			cg_phase;	/* code generation phase */
 GBLREF char			cg_phase_last;	/* previous code generation phase */
 GBLREF int4			curr_addr, code_size;
 GBLREF char			object_file_name[];
+GBLREF int			object_file_des;
 
+error_def(ERR_SYSCALL);
 error_def(ERR_TEXT);
 
 void	cg_lab (mlabel *l, int4 base);
@@ -85,6 +87,7 @@ void	cg_lab (mlabel *l, int4 base);
 
 void	obj_code (uint4 src_lines, void *checksum_ctx)
 {
+	int		status;
 	rhdtyp		rhead;
 	mline		*mlx, *mly;
 	var_tabent	*vptr;
@@ -171,13 +174,16 @@ void	obj_code (uint4 src_lines, void *checksum_ctx)
 	}
 	if (0 != lnr_pad_len) /* emit padding so literal text pool starts on proper boundary */
 		emit_immed(PADCHARS, lnr_pad_len);
-#if !defined(__MVS__) && !defined(__s390__)	/* assert not valid for instructions on OS390 */
+#	if !defined(__MVS__) && !defined(__s390__)	/* assert not valid for instructions on OS390 */
 	assert(code_size == psect_use_tab[GTM_CODE]);
-#endif
+#	endif
 	emit_literals();
-	close_object_file();
+	finish_object_file();
+	CLOSE_OBJECT_FILE(object_file_des, status);
+	if (-1 == status)
+		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, errno);
 	/* Ready to make object visible. Rename from tmp name to real routine name */
-	rename_tmp_object_file(object_file_name);
+	RENAME_TMP_OBJECT_FILE(object_file_name);
 }
 
 void	cg_lab (mlabel *l, int4 base)
diff --git a/sr_unix_nsb/obj_filesp.h b/sr_unix_nsb/obj_filesp.h
index cf8526d..1055bc8 100644
--- a/sr_unix_nsb/obj_filesp.h
+++ b/sr_unix_nsb/obj_filesp.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2004 Sanchez Computer Associates, Inc.	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -12,14 +12,8 @@
 #ifndef OBJ_FILESP_INCLUDED
 #define OBJ_FILESP_INCLUDED
 
-#ifdef __sparc
-	void emit_addr(int4 refaddr_upper, int4 refaddr_lower, int4 offset, int4 *result_upper, int4 *result_lower);
-	void emit_reference(uint4 refaddr_upper, uint4 refaddr_lower, mstr *name, uint4 *result_upper,   uint4 *result_lower);
-#else
-	void emit_addr(int4 refaddr, int4 offset, int4 *result);
-	void emit_reference(uint4 refaddr, mstr *name, uint4 *result);
-#endif
-
+void emit_addr(int4 refaddr, int4 offset, int4 *result);
+void emit_reference(uint4 refaddr, mstr *name, uint4 *result);
 struct sym_table *define_symbol(unsigned char psect, mstr *name, int4 value);
 void emit_pidr(int4 refoffset, int4 data_offset, int4 *result);
 void buff_emit(void);
diff --git a/sr_unix_nsb/rtnhdr.h b/sr_unix_nsb/rtnhdr.h
index 295db6e..73e7ed6 100644
--- a/sr_unix_nsb/rtnhdr.h
+++ b/sr_unix_nsb/rtnhdr.h
@@ -95,7 +95,7 @@ typedef struct	rhead_struct
 #	ifdef GTM_TRIGGER
 	void_ptr_t	trigr_handle;		/* Type is void to avoid needing gv_trigger.h to define gv_trigger_t addr */
 #	endif
-	unsigned char	checksum_md5[16];	/* 16-byte MD5 checksum of routine source code */
+	unsigned char	checksum_128[16];	/* 16-byte MurmurHash3 checksum of routine source code */
 	routine_source	*source_code;		/* source code used by $TEXT */
 	uint4		routine_source_offset;	/* (updated) when compiled with EMBED_SOURCE: offset of M source within literal text
 						 * pool; becomes absolute address in incr_link
@@ -144,7 +144,7 @@ typedef struct
 #define VERIFY		TRUE
 #define NOVERIFY	FALSE
 
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
 void free_src_tbl(rhdtyp *rtn_vector);
 unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
 int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
diff --git a/sr_vvms/dbcertify_exit_handler.c b/sr_vvms/dbcertify_exit_handler.c
index ebc8ef4..92bf3bf 100644
--- a/sr_vvms/dbcertify_exit_handler.c
+++ b/sr_vvms/dbcertify_exit_handler.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2005, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2005, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -105,7 +105,7 @@ void dbcertify_exit_handler(void)
 		 * But the commit phase (beginning from when early_tn is curr_tn + 1 to when they become equal) is a relatively
 		 * 	finite window wherefrom we are guaranteed to return.
 		 */
-		if (psa_gbl->dbc_critical)
+		if ((NULL != psa_gbl) && psa_gbl->dbc_critical)
 		{
 			EXIT_HANDLER(&exi_blk);
 			ESTABLISH(exi_ch);
@@ -117,8 +117,11 @@ void dbcertify_exit_handler(void)
 	print_exit_stats();
 	if (0 == exi_condition)
 		exi_condition = ERR_UNKNOWNFOREX;
-	if (psa_gbl->phase_one)
-		dbc_scan_phase_cleanup();
-	else
-		dbc_certify_phase_cleanup();
+	if (NULL != psa_gbl)
+	{
+		if (psa_gbl->phase_one)
+			dbc_scan_phase_cleanup();
+		else
+			dbc_certify_phase_cleanup();
+	}
 }
diff --git a/sr_vvms/get_src_line.c b/sr_vvms/get_src_line.c
index 040f914..756ca4b 100644
--- a/sr_vvms/get_src_line.c
+++ b/sr_vvms/get_src_line.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -29,7 +29,7 @@
 
 #define RT_TBL_SZ 20
 
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig)
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec)
 {
 	struct FAB		fab;
 	struct RAB		rab;
@@ -60,10 +60,20 @@ int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_
 		op_zlink(routine, NULL);
 		rtn_vector = find_rtn_hdr(&routine->str);
 		if (!rtn_vector)
+		{
+			if (NULL != rtn_vec)
+				*rtn_vec = NULL;
 			return OBJMODMISS;
+		}
 	}
 	if (!rtn_vector->src_full_name.len)
+	{
+		if (NULL != rtn_vec)
+			*rtn_vec = NULL;
 		return SRCNOTAVAIL;
+	}
+	if (NULL != rtn_vec)
+		*rtn_vec = rtn_vector;
 	rtnent.var_name = rtn_vector->routine_name;
 	COMPUTE_HASH_MNAME(&rtnent);
 	added = add_hashtab_mname(TADR(rt_name_tbl), &rtnent, NULL, &tabent);
diff --git a/sr_vvms/gt_timers.c b/sr_vvms/gt_timers.c
index 42b4963..c8e90bb 100644
--- a/sr_vvms/gt_timers.c
+++ b/sr_vvms/gt_timers.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2007 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -14,7 +14,7 @@
  * Following routines are top level, user callable
  * routines of this package:
  *
- * void sys_get_cur_time(ABS_TIME atp)
+ * void sys_get_curr_time(ABS_TIME atp)
  * 	fetch absolute time into stucture
  *
  * void hiber_start(uint4 hiber)
@@ -62,7 +62,7 @@ void sys_get_curr_time(ABS_TIME *atp)
 		atp->at_sec = (uint4)(((((double)systim[1]) * MAX_INT) + (double)systim[0]) / 10000000.0);
 		return;
 	}
-	rts_error(VARLSTCNT(1) status);
+	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
 }
 
 static void hiber_start_ast(void)
diff --git a/sr_vvms/gtm$startup.c b/sr_vvms/gtm$startup.c
index 83e01c3..84ad838 100644
--- a/sr_vvms/gtm$startup.c
+++ b/sr_vvms/gtm$startup.c
@@ -259,7 +259,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
 		if (0 != svec->user_spawn_flag)
 		{
 		        if (SS$_NORMAL != (trust_status = sys$getjpiw(EFN$C_ENF, 0, 0, item_list, 0, 0, 0)))
-			        rts_error(VARLSTCNT(1) trust_status);
+			        rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) trust_status);
 			else if (imagpriv & PRV$M_CMEXEC)
 			       trust = svec->user_spawn_flag;
 		}
@@ -351,7 +351,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
 		} else
 		{
 			licensed = FALSE;
-			rts_error(VARLSTCNT(1) status);
+			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
 		}
 #		endif
 		jobinterrupt_init();
@@ -416,6 +416,7 @@ void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
 		assert(FALSE == curr_symval->alias_activity);
 		curr_symval->alias_activity = TRUE;
 		lvzwr_init(0, (mval *)NULL);
+		TREF(in_zwrite) = FALSE;
 		curr_symval->alias_activity = FALSE;
 		/* Initialize cache structure for $Piece function (except for Vax which does not use this) */
 		for (i = 0; FNPC_MAX > i; i++)
diff --git a/sr_vvms/gtm_logicals.h b/sr_vvms/gtm_logicals.h
index 6c70468..e167838 100644
--- a/sr_vvms/gtm_logicals.h
+++ b/sr_vvms/gtm_logicals.h
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -16,14 +16,15 @@
 #define	GTM_DIST_LOG			"GTM$DIST"
 
 /* Database */
-#define	GTM_GBLDIR			"GTM$GBLDIR"
 #define	GTM_BLKUPGRADE_FLAG		"GTM_BLKUPGRADE_FLAG"
 #define	GTM_DBFILEXT_SYSLOG_DISABLE	"GTM_DBFILEXT_SYSLOG_DISABLE"
 #define	GTM_ENV_XLATE			"GTM_ENV_TRANSLATE"
 #define	GTM_FULLBLOCKWRITES		"GTM_FULLBLOCKWRITES"
 #define	GTM_GDSCERT			"GTM_GDSCERT"
+#define	GTM_GBLDIR			"GTM$GBLDIR"
 #define	GTM_GVDUPSETNOOP		"GTM_GVDUPSETNOOP"
 #define	GTM_GVUNDEF_FATAL		"GTM_GVUNDEF_FATAL"
+#define	GTM_POOLLIMIT			"GTM_POOLLIMIT"
 #define	GTM_TP_ALLOCATION_CLUE		"GTM_TP_ALLOCATION_CLUE"
 #define	GTM_TPNOTACIDTIME		"GTM_TPNOTACIDTIME"
 #define	GTM_TPRESTART_LOG_DELTA		"GTM_TPRESTART_LOG_DELTA"
diff --git a/sr_vvms/gtmrecv_process.c b/sr_vvms/gtmrecv_process.c
index c750e41..41711df 100644
--- a/sr_vvms/gtmrecv_process.c
+++ b/sr_vvms/gtmrecv_process.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ *	Copyright 2006, 2014 Fidelity Information Services, Inc.*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
@@ -121,7 +121,6 @@ error_def(ERR_REPLCOMM);
 error_def(ERR_REPLGBL2LONG);
 error_def(ERR_REPLTRANS2BIG);
 error_def(ERR_REPLWARN);
-error_def(ERR_SECNODZTRIGINTP);
 error_def(ERR_TEXT);
 error_def(ERR_UNIMPLOP);
 
@@ -672,9 +671,6 @@ static void process_tr_buff(void)
 									(unsigned int)jnl_dest_maxrectype);
 						else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno)
 								rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);
-						else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
-							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1,
-									&recvpool_ctl->jnl_seqno);
 						else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */
 							assertpro(repl_errno != repl_errno);
 					}
diff --git a/sr_port/lastchance1.c b/sr_vvms/lastchance1.c
similarity index 100%
rename from sr_port/lastchance1.c
rename to sr_vvms/lastchance1.c
diff --git a/sr_port/lastchance2.c b/sr_vvms/lastchance2.c
similarity index 95%
rename from sr_port/lastchance2.c
rename to sr_vvms/lastchance2.c
index 8a2f872..689ba51 100644
--- a/sr_port/lastchance2.c
+++ b/sr_vvms/lastchance2.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2012 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
diff --git a/sr_port/lastchance3.c b/sr_vvms/lastchance3.c
similarity index 94%
rename from sr_port/lastchance3.c
rename to sr_vvms/lastchance3.c
index 991e2cd..d53ea9c 100644
--- a/sr_port/lastchance3.c
+++ b/sr_vvms/lastchance3.c
@@ -1,6 +1,6 @@
 /****************************************************************
  *								*
- *	Copyright 2001, 2013 Fidelity Information Services, Inc	*
+ *	Copyright 2001, 2014 Fidelity Information Services, Inc	*
  *								*
  *	This source code contains the intellectual property	*
  *	of its copyright holder(s), and is made available	*
diff --git a/sr_vvms/op_fnzsearch.c b/sr_vvms/op_fnzsearch.c
index 88cacb1..a70bf34 100644
--- a/sr_vvms/op_fnzsearch.c
+++ b/sr_vvms/op_fnzsearch.c
@@ -64,7 +64,7 @@ int op_fnzsearch(mval *file, mint strm, mint mcmd, mval *ret)
 	}
 	assert(fab_sea != 0);
 	index = (short)strm;
-	if (mcmd && ((MAX_STRM_CT < index) || ( 0 > index)))	/* Bypass stream check for internal uses */
+	if (mcmd && ((MAX_STRM_CT <= index) || ( 0 > index)))	/* Bypass stream check for internal uses */
 		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZSRCHSTRMCT);
 	MV_FORCE_STR(file);
 	if (file->str.len > MAX_FN_LEN)
diff --git a/sr_port/op_setzbrk.c b/sr_vvms/op_setzbrk.c
similarity index 75%
copy from sr_port/op_setzbrk.c
copy to sr_vvms/op_setzbrk.c
index 7720e3e..aa6cf1f 100644
--- a/sr_port/op_setzbrk.c
+++ b/sr_vvms/op_setzbrk.c
@@ -30,9 +30,14 @@
 #include "gtm_text_alloc.h"
 #include "srcline.h"
 #include "compiler.h"
+#include "min_max.h"
 #ifdef GTM_TRIGGER
 # include "trigger_source_read_andor_verify.h"
 # include "gtm_trigger_trc.h"
+#else
+# define DBGIFTRIGR(x)
+# define DBGTRIGR(x)
+# define DBGTRIGR_ONLY(x)
 #endif
 
 GBLREF z_records		zbrk_recs;
@@ -57,7 +62,7 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	char		*cp, zbloc_buff[MAX_ENTRYREF_LEN], *zbloc_end;
 	mident		*lab_name, *dummy;
 	mident		rname, lname;
-	mstr		*obj;
+	mstr		*obj, tmprtnname;
 	rhdtyp		*routine;
 	zb_code		*addr, tmp_xf_code;
 	int4		*line_offset_addr, *next_line_offset_addr;
@@ -67,7 +72,8 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	uint4		status;
 	int		sstatus;
 	icode_str	indir_src;
-	boolean_t	deleted, is_trigger;
+	boolean_t	deleted;
+	GTMTRIG_ONLY(boolean_t	is_trigger);
 
 	MV_FORCE_STR(rtn);
 	MV_FORCE_STR(lab);
@@ -83,18 +89,26 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 	else
 	{
 		GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
-		GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n")));
+		DBGIFTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n"));
 		flush_pio();
 		if (WANT_CURRENT_RTN(rtn))
 			routine = CURRENT_RHEAD_ADR(frame_pointer->rvector);
 		else if (NULL == (routine = find_rtn_hdr(&rtn->str)))	/* Note assignment */
 		{
 #			ifdef GTM_TRIGGER
+			/* trigger_source_read_andor_verify may alter the length part of the mstr to remove the +BREG
+			 * region-name specification (the string component is unmodified). Pass in a copy of the mstr
+			 * struct to avoid modification to routine->str as it affects the caller which relies on this
+			 * variable being untouched.
+			 */
+			tmprtnname = rtn->str;
 			if (is_trigger)
 			{
-				sstatus = trigger_source_read_andor_verify(&rtn->str, TRIGGER_COMPILE);
-				if ((0 != sstatus) || (NULL == (routine = find_rtn_hdr(&rtn->str))))	/* Note assignment */
+				DEBUG_ONLY(routine = NULL;)
+				sstatus = trigger_source_read_andor_verify(&tmprtnname, TRIGGER_COMPILE, &routine);
+				if (0 != sstatus)
 					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
+				assert(NULL != routine);
 			} else
 #			endif
 			{
@@ -108,26 +122,26 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 		lab_name = NULL;
 		if (NULL == (line_offset_addr = find_line_addr(routine, &lab->str, offset, &lab_name)))
 			dec_err(VARLSTCNT(1) ERR_NOPLACE);
-		else if (CANCEL_ONE == cnt)		/* cancel zbreak */
+		else if (CANCEL_ONE == cnt)	/* Cancel ZBREAK */
 		{
 			addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
 			addr = find_line_call(addr);
 			if (NULL != (z_ptr = zr_find(&zbrk_recs, addr)))
-				zr_put_free(&zbrk_recs, z_ptr);
+				zr_remove_zbreak(&zbrk_recs, z_ptr);
 			else
 				dec_err(VARLSTCNT(1) ERR_NOZBRK);
-		} else if (0 <= cnt)		/* set zbreak */
+		} else if (0 <= cnt)		/* Set ZBREAK */
 		{
 #			ifdef ZB_AT_COMMENT_INFO
 			dummy = NULL;
 			next_line_offset_addr = find_line_addr(routine, &lab->str, offset + 1, &dummy);
 			if (NULL != next_line_offset_addr && *next_line_offset_addr == *line_offset_addr)
-			{ /* we don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
+			{ 	/* We don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
 				dec_err(VARLSTCNT(1) ERR_COMMENT);
 				assert(lab_name == dummy);
 			}
 #			endif
-			op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
+			op_commarg(act, indir_linetail); 	/* This puts entry in stack and also increments refcnt field */
 			indir_src.str = act->str;
 			indir_src.code = indir_linetail;
 			obj = cache_get(&indir_src);
@@ -146,14 +160,14 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 			{
 #				ifdef USHBIN_SUPPORTED
 				if ((NULL != routine->shared_ptext_adr) && (routine->shared_ptext_adr == routine->ptext_adr))
-				{	/* setting a breakpoint in a shared routine, need to make a private copy */
+				{	/* Setting a breakpoint in a shared routine, need to make a private copy */
 					addr_off = (unsigned char *)addr - routine->ptext_adr;
 					if (SS_NORMAL == (status = cre_private_code_copy(routine)))
 						addr = (zb_code *)(routine->ptext_adr + addr_off);
 					else
 					{
 						assert(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY) == status);
-						/* convert to label+offset^routine to be presented to the user */
+						/* Convert to label+offset^routine to be presented to the user */
 						rname.len = rtn->str.len;
 						rname.addr = rtn->str.addr;
 						lname.len = lab->str.len;
@@ -164,15 +178,21 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 					}
 				}
 #				endif
-				z_ptr = zr_get_free(&zbrk_recs, addr);
+				z_ptr = zr_add_zbreak(&zbrk_recs, addr);
 				NON_USHBIN_ONLY(fix_pages((unsigned char *)addr, (unsigned char *)addr));
-
-				/* save for later restore while cancelling breakpoint */
+				/* Modify the instruction at the ZBREAK site. See zbreaksp.h for description of how this works
+				 * on a given platform.
+				 *
+				 * Save original instruction for later restore when cancelling this breakpoint.
+				 */
 #				ifdef	COMPLEX_INSTRUCTION_UPDATE
 				EXTRACT_OFFSET_TO_M_OPCODE(z_ptr->m_opcode, addr);
 #				else
-				z_ptr->m_opcode = *addr; /* save for later restore while cancelling breakpoint */
+				z_ptr->m_opcode = *addr;
 #				endif
+				/* Modify op_linestart or op_linefetch transfer table reference instruction to the appropriate
+				 * ZBREAK related flavor of instruction instead.
+				 */
 				tmp_xf_code = (z_ptr->m_opcode & ZB_CODE_MASK) >> ZB_CODE_SHIFT;
 				if (xf_linefetch * SIZEOF(UINTPTR_T) == tmp_xf_code)
 				{
@@ -194,18 +214,21 @@ void	op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
 					assertpro( ((xf_zbstart * SIZEOF(UINTPTR_T)) == tmp_xf_code)
 						|| ((xf_zbfetch * SIZEOF(UINTPTR_T)) == tmp_xf_code));
 				z_ptr->rtn = &(CURRENT_RHEAD_ADR(routine))->routine_name;
-				assert(lab_name != NULL);
+				assert(NULL != lab_name);
 				z_ptr->lab = lab_name;
 				z_ptr->offset = offset;
 				z_ptr->mpc = (zb_code *)((unsigned char *)addr - SIZEOF_LA);
+				z_ptr->rtnhdr = routine;
+				USHBIN_ONLY(routine->has_ZBREAK = TRUE);	/* USHBIN platforms know which rtns have ZBREAK */
 				inst_flush(addr, SIZEOF(INST_TYPE));
 			}
 			if (z_ptr->action)
-			{	/* A zbreak command was already set for this line */
-				/* Note when new action is same as old action, no resultant changes in zb_refcnt */
-				assert(z_ptr->action->zb_refcnt > 0);
+			{	/* A ZBREAK command was already set for this line. Note when new action is same as
+				 * old action, no resultant changes in zb_refcnt.
+				 */
+				assert(0 <z_ptr->action->zb_refcnt);
 				z_ptr->action->zb_refcnt--;
-				assert(z_ptr->action != csp || z_ptr->action->zb_refcnt > 0);
+				assert((z_ptr->action != csp) || (0 <z_ptr->action->zb_refcnt));
 			}
 			z_ptr->action = csp;
 			z_ptr->count = cnt;
diff --git a/sr_vvms/rtnhdr.h b/sr_vvms/rtnhdr.h
index 3bb5525..1343001 100644
--- a/sr_vvms/rtnhdr.h
+++ b/sr_vvms/rtnhdr.h
@@ -136,7 +136,7 @@ typedef struct
 #define VERIFY		TRUE
 #define NOVERIFY	FALSE
 
-int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, rhdtyp **rtn_vec);
 void free_src_tbl(rhdtyp *rtn_vector);
 unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
 int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
diff --git a/sr_x86_64/merrors_ansi.h b/sr_x86_64/merrors_ansi.h
index 20e9320..f00646a 100644
--- a/sr_x86_64/merrors_ansi.h
+++ b/sr_x86_64/merrors_ansi.h
@@ -609,7 +609,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* FREEZEID */
 	   0,	/* BLKWRITERR */
 	   0,	/* STOPTIMEOUT */
-	   0,	/* TRIGMODINTP */
+	   0,	/* UNUSEDMSG776 */
 	   0,	/* BCKUPBUFLUSH */
 	   0,	/* NOFORKCORE */
 	   0,	/* JNLREAD */
@@ -731,7 +731,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* SCNDDBNOUPD */
 	   0,	/* MUINFOUINT4 */
 	   0,	/* NLMISMATCHCALC */
-	   0,	/* UNUSEDMSG898 */
+	   0,	/* RELINKCTLFULL */
 	   0,	/* UNUSEDMSG899 */
 	   0,	/* DBBADNSUB */
 	   0,	/* DBBADKYNM */
@@ -1200,13 +1200,13 @@ const static readonly int error_ansi[] = {
 	   0,	/* SSATTACHSHM */
 	   0,	/* TRIGDEFNOSYNC */
 	   0,	/* TRESTMAX */
-	   0,	/* UNUSEDMSG1367 */
+	   0,	/* ZLINKBYPASS */
 	   0,	/* GBLEXPECTED */
 	   0,	/* GVZTRIGFAIL */
 	   0,	/* MUUSERLBK */
 	   0,	/* SETINSETTRIGONLY */
 	   0,	/* DZTRIGINTRIG */
-	   0,	/* SECNODZTRIGINTP */
+	   0,	/* UNUSEDMSG1373 */
 	   0,	/* BOOLSIDEFFECT */
 	   0,	/* DBBADUPGRDSTATE */
 	   0,	/* WRITEWAITPID */
@@ -1218,7 +1218,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* JNLORDBFLU */
 	   0,	/* ZCCLNUPRTNMISNG */
 	   0,	/* ZCINVALIDKEYWORD */
-	   0,	/* REPLNOMULTILINETRG */
+	   0,	/* UNUSEDMSG1385 */
 	   0,	/* DBSHMNAMEDIFF */
 	   0,	/* SHMREMOVED */
 	   0,	/* DEVICEWRITEONLY */
@@ -1370,7 +1370,7 @@ const static readonly int error_ansi[] = {
 	   0,	/* ISSPANGBL */
 	   0,	/* TPNOSUPPORT */
 	   0,	/* GVSUBSERR */
-	   0,	/* TRIGNOSPANGBL */
+	   0,	/* UNUSEDMSG1539 */
 	   0,	/* FILTERTIMEDOUT */
 	   0,	/* TLSDLLNOOPEN */
 	   0,	/* TLSINIT */
@@ -1407,4 +1407,19 @@ const static readonly int error_ansi[] = {
 	  13,	/* LABELNOTFND */
 	   0,	/* RELINKCTLERR */
 	   0,	/* INVLINKTMPDIR */
+	   0,	/* NOEDITOR */
+	   0,	/* UPDPROC */
+	   0,	/* HLPPROC */
+	   0,	/* REPLNOHASHTREC */
+	   0,	/* REMOTEDBNOTRIG */
+	   0,	/* NEEDTRIGUPGRD */
+	   0,	/* REQRLNKCTLRNDWN */
+	   0,	/* RLNKCTLRNDWNSUC */
+	   0,	/* RLNKCTLRNDWNFL */
+	   0,	/* MPROFRUNDOWN */
+	   0,	/* ZPEEKNOJNLINFO */
+	   0,	/* TLSPARAM */
+	   0,	/* RLNKRECLATCH */
+	   0,	/* RLNKSHMLATCH */
+	   0,	/* JOBLVN2LONG */
 	};
diff --git a/sr_x86_64/merrors_ctl.c b/sr_x86_64/merrors_ctl.c
index 4c4ea08..fc01b83 100644
--- a/sr_x86_64/merrors_ctl.c
+++ b/sr_x86_64/merrors_ctl.c
@@ -330,7 +330,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"LDBINFMT", "Unrecognized header for load file", 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,
@@ -413,7 +413,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"JNLBADLABEL", "Journal file !AD has a bad GT.M Journal File Label. Expected !AD. Found !AD.", 6,
 	"JNLREADEOF", "End of journal file encountered for !AD", 2,
 	"JNLRECFMT", "Journal file record format error encountered", 0,
 	"BLKTOODEEP", "Block level too deep", 0,
@@ -611,7 +611,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"UNUSEDMSG776", "TRIGMODINTP last used in V6.2-000", 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,
@@ -644,7 +644,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
-	"RECLOAD", "Error loading record number: !UL!/", 1,
+	"RECLOAD", "Error loading record number: !@UQ!/", 1,
 	"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,
@@ -733,7 +733,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"RELINKCTLFULL", "Relinkctl file for directory !AD is full (maximum entries !UL)", 3,
 	"UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0,
 	"DBBADNSUB", "!AD Bad numeric subscript", 2,
 	"DBBADKYNM", "!AD Bad key name", 2,
@@ -1202,13 +1202,13 @@ LITDEF	err_msg merrors[] = {
 	"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 at XQ", 7,
 	"TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0,
-	"UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
+	"ZLINKBYPASS", "ZLINK of !AD bypassed - Identical routine already linked", 2,
 	"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 at 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,
+	"UNUSEDMSG1373", "SECNODZTRIGINTP : Last used in V6.2-000", 0,
 	"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,
@@ -1220,7 +1220,7 @@ LITDEF	err_msg merrors[] = {
 	"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 at XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1,
+	"UNUSEDMSG1385", "REPLNOMULTILINETRG : Last used in V6.2-000", 0,
 	"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,
@@ -1240,7 +1240,7 @@ LITDEF	err_msg merrors[] = {
 	"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,
+	"TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted/upgraded 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,
@@ -1372,7 +1372,7 @@ LITDEF	err_msg merrors[] = {
 	"ISSPANGBL", "Operation cannot be performed on global ^!AD as it spans multiple regions in current global directory", 2,
 	"TPNOSUPPORT", "Operation cannot be performed while inside of a TP transaction", 0,
 	"GVSUBSERR", "Invalid subscripted global name specification in $VIEW() function", 0,
-	"TRIGNOSPANGBL", "Triggers cannot be installed/deleted for global name !AD as it spans multiple regions in current global directory", 2,
+	"UNUSEDMSG1539", "TRIGNOSPANBL : Last used in V6.2-000", 0,
 	"FILTERTIMEDOUT", "Replication server timed out attempting to read seqno !16 at XQ from external filter", 1,
 	"TLSDLLNOOPEN", "Failed to load GT.M TLS/SSL library for secure communication", 0,
 	"TLSINIT", "Failed to initialize GT.M TLS/SSL library for secure communication", 0,
@@ -1409,6 +1409,21 @@ LITDEF	err_msg merrors[] = {
 	"LABELNOTFND", "GOTO referenced a label that does not exist", 0,
 	"RELINKCTLERR", "Error with relink control structure for $ZROUTINES directory !AD", 2,
 	"INVLINKTMPDIR", "Value for $gtm_linktmpdir is either not found or not a directory: !AD", 2,
+	"NOEDITOR", "Can't find an executable editor: !AD", 2,
+	"UPDPROC", "Update Process error", 0,
+	"HLPPROC", "Helper Process error", 0,
+	"REPLNOHASHTREC", "Sequence number 0x!16 at XQ contains trigger definition updates. !AD side must be at least V6.2-000 for replication to continue", 3,
+	"REMOTEDBNOTRIG", "Trigger operations on global !AD not supported as it maps to database region !AD that points to a remote file", 4,
+	"NEEDTRIGUPGRD", "Cannot do trigger operation on database file !AD until it is upgraded; Run MUPIP TRIGGER -UPGRADE first", 2,
+	"REQRLNKCTLRNDWN", "Error accessing relinkctl file for $ZROUTINES directory !AD. Must be rundown", 2,
+	"RLNKCTLRNDWNSUC", "Relinkctl file for $ZROUTINES directory !AD successfully rundown", 2,
+	"RLNKCTLRNDWNFL", "Relinkctl file for $ZROUTINES directory !AD failed to rundown as it is open by !UL process(es)", 3,
+	"MPROFRUNDOWN", "Error during M-profiling rundown", 0,
+	"ZPEEKNOJNLINFO", "$ZPEEK() unable to access requested journal structure - region !AD is not currently journaled", 2,
+	"TLSPARAM", "TLS parameter !AD !AD", 4,
+	"RLNKRECLATCH", "Failed to get latch on relinkctl record for routine name !AZ in $ZROUTINES directory !AD", 3,
+	"RLNKSHMLATCH", "Failed to get latch on relinkctl shared memory for $ZROUTINES directory !AD", 2,
+	"JOBLVN2LONG", "The zwrite representation of a local variable transferred to a JOB'd process can not exceed !UL. Encountered size: !UL", 2,
 };
 
 LITDEF	int ERR_ACK = 150372361;
@@ -2009,7 +2024,7 @@ 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_UNUSEDMSG776 = 150377146;
 LITDEF	int ERR_BCKUPBUFLUSH = 150377154;
 LITDEF	int ERR_NOFORKCORE = 150377160;
 LITDEF	int ERR_JNLREAD = 150377170;
@@ -2131,7 +2146,7 @@ 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_RELINKCTLFULL = 150378122;
 LITDEF	int ERR_UNUSEDMSG899 = 150378131;
 LITDEF	int ERR_DBBADNSUB = 150378138;
 LITDEF	int ERR_DBBADKYNM = 150378146;
@@ -2600,13 +2615,13 @@ 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_ZLINKBYPASS = 150381875;
 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_UNUSEDMSG1373 = 150381922;
 LITDEF	int ERR_BOOLSIDEFFECT = 150381928;
 LITDEF	int ERR_DBBADUPGRDSTATE = 150381936;
 LITDEF	int ERR_WRITEWAITPID = 150381946;
@@ -2618,7 +2633,7 @@ 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_UNUSEDMSG1385 = 150382018;
 LITDEF	int ERR_DBSHMNAMEDIFF = 150382026;
 LITDEF	int ERR_SHMREMOVED = 150382035;
 LITDEF	int ERR_DEVICEWRITEONLY = 150382042;
@@ -2770,7 +2785,7 @@ LITDEF	int ERR_GBLNOMAPTOREG = 150383202;
 LITDEF	int ERR_ISSPANGBL = 150383210;
 LITDEF	int ERR_TPNOSUPPORT = 150383218;
 LITDEF	int ERR_GVSUBSERR = 150383226;
-LITDEF	int ERR_TRIGNOSPANGBL = 150383234;
+LITDEF	int ERR_UNUSEDMSG1539 = 150383234;
 LITDEF	int ERR_FILTERTIMEDOUT = 150383242;
 LITDEF	int ERR_TLSDLLNOOPEN = 150383250;
 LITDEF	int ERR_TLSINIT = 150383258;
@@ -2807,9 +2822,24 @@ LITDEF	int ERR_CRYPTBADWRTPOS = 150383498;
 LITDEF	int ERR_LABELNOTFND = 150383506;
 LITDEF	int ERR_RELINKCTLERR = 150383514;
 LITDEF	int ERR_INVLINKTMPDIR = 150383522;
+LITDEF	int ERR_NOEDITOR = 150383530;
+LITDEF	int ERR_UPDPROC = 150383538;
+LITDEF	int ERR_HLPPROC = 150383546;
+LITDEF	int ERR_REPLNOHASHTREC = 150383554;
+LITDEF	int ERR_REMOTEDBNOTRIG = 150383562;
+LITDEF	int ERR_NEEDTRIGUPGRD = 150383570;
+LITDEF	int ERR_REQRLNKCTLRNDWN = 150383578;
+LITDEF	int ERR_RLNKCTLRNDWNSUC = 150383587;
+LITDEF	int ERR_RLNKCTLRNDWNFL = 150383594;
+LITDEF	int ERR_MPROFRUNDOWN = 150383602;
+LITDEF	int ERR_ZPEEKNOJNLINFO = 150383610;
+LITDEF	int ERR_TLSPARAM = 150383618;
+LITDEF	int ERR_RLNKRECLATCH = 150383626;
+LITDEF	int ERR_RLNKSHMLATCH = 150383634;
+LITDEF	int ERR_JOBLVN2LONG = 150383642;
 
 GBLDEF	err_ctl merrors_ctl = {
 	246,
 	"GTM",
 	&merrors[0],
-	1396};
+	1411};
diff --git a/sr_x86_64/obj_filesp.c b/sr_x86_64/obj_filesp.c
index 5366dfd..625bf95 100644
--- a/sr_x86_64/obj_filesp.c
+++ b/sr_x86_64/obj_filesp.c
@@ -122,7 +122,7 @@ void create_object_file(rhdtyp *rhead)
 	/* Action instructions and marker are not kept in the same array since the type of the elements of
 	 * the former (uint4) may be different from the type of the elements of the latter (char).
 	 * 'tiz cleaner this way rather than converting one to the other type in order to be accommodated
-	 * in an array
+	 * in an array.
 	 */
         assert(JSB_ACTION_N_INS * SIZEOF(jsb_action[0]) == SIZEOF(jsb_action));	/* JSB_ACTION_N_INS maintained? */
         assert(SIZEOF(jsb_action) <= SIZEOF(rhead->jsb));			/* Overflow check */
@@ -135,8 +135,9 @@ void create_object_file(rhdtyp *rhead)
 
 /* At this point, we know only gtm_object has been written onto the file.
  * Read that gtm_object and wrap it up in .text section, add remaining sections to native object(ELF)
- * Update the ELF, write it out to the object file and close the object file */
-void close_object_file(void)
+ * Update the ELF, write it out to the object file and close the object file.
+ */
+void finish_object_file(void)
 {
         int		i, status;
         size_t		bufSize;
@@ -324,7 +325,5 @@ void close_object_file(void)
         /* Free the memory malloc'ed above */
         free(string_tbl);
         free(gtm_obj_code);
-	if ((off_t)-1 == lseek(object_file_des, (off_t)0, SEEK_SET))
-		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/fis-gtm.git



More information about the debian-med-commit mailing list